Forwarded from Чудин белоглазый wrote
Самая противная иллюзия, которую положили мне в голову в детстве, заключается в том, что если кто-то что-то не понимает, значит ты недостаточно хорошо объяснил.
К себе, понятно, этот критерий ни родители, ни учителя никогда не применяли. А я поверил и взял его, как базовый. И вот только пару лет назад начало доходить, что нет, это работает не так. И если человек чего-то не понимает, настойчиво и упорно, то он и не хочет понимать. И никогда не захочет.
И действовать исходя из этого знания куда полезнее, чем ломиться в закрытые ворота человека, который не намерен уточнять свои знания об окружающем мире.
К себе, понятно, этот критерий ни родители, ни учителя никогда не применяли. А я поверил и взял его, как базовый. И вот только пару лет назад начало доходить, что нет, это работает не так. И если человек чего-то не понимает, настойчиво и упорно, то он и не хочет понимать. И никогда не захочет.
И действовать исходя из этого знания куда полезнее, чем ломиться в закрытые ворота человека, который не намерен уточнять свои знания об окружающем мире.
🕊14❤9🐳2🌭2💩1🌚1
#prog #rust
Кажется, что такой код должен работать:
Как именно решать эту проблему — непонятно, равно как и решить, как именно нужно запилить vtable так, чтобы они работали с такими кастами и при этом не жрали кучу места. Отдельной пикантности добавляет тот факт, что unsize-касты сырых указателей уже есть и разрешены в safe-коде.
А что делать, пока нужный функционал не реализовали нативно? Явно внедрить метод для апкаста:
Подробности.
Кажется, что такой код должен работать:
trait Super {}
trait Sub: Super {}
fn upcast(x: &dyn Sub) -> &dyn Super {
x as &dyn Super
}
Но нет, он валится с ошибкой. Такой, казалось бы, очевидный функционал был описан в RFC от 2013 (!) года и при этом до сих пор не реализован. Почему? Ну, его начали было реализовывать — и натолкнулись на непонятки с кастами сырых указателей на трейт-объекты: просто добавление функционала апкаста может вызвать UB в safe Rust, поскольку этот апкаст должен каким-то образом поменять vtable-составляющую, а эта часть сырого указателя может быть просто мусором.Как именно решать эту проблему — непонятно, равно как и решить, как именно нужно запилить vtable так, чтобы они работали с такими кастами и при этом не жрали кучу места. Отдельной пикантности добавляет тот факт, что unsize-касты сырых указателей уже есть и разрешены в safe-коде.
А что делать, пока нужный функционал не реализовали нативно? Явно внедрить метод для апкаста:
trait Super {}
trait AsSuper {
fn as_super(&self) -> &dyn Super;
}
trait Sub: Super + AsSuper {}
fn upcast(x: &dyn Sub) -> &dyn Super {
x.as_super()
}
Да, при это добавляется неприятный бойлерплейт видаimpl AsSuper for Type {
fn as_super(&self) -> &dyn Super {
self
}
}
, но так оно хотя бы работает. Аналогично можно сделать методы для каста между уникальными ссылками и умными указателями. И нет, blanket impl тут сделать нельзя, потому что тип для избежания каста между трейт-объектами должен быть Sized
, что ломает весь смысл в данной конструкции.Подробности.
GitHub
Objects should be upcastable to supertraits · Issue #2765 · rust-lang/rfcs
trait T { fn foo(@mut self); } struct S { unused: int } impl T for S { fn foo(@mut self) { } } fn main() { let s = @S { unused: 0 }; let s2 = s as @T; let s3 = s2 as @T; } error: failed to find an ...
👍5
#prog #rust #rustlib
rustversion
This crate provides macros for conditional compilation according to rustc compiler version, analogous to
rustversion
This crate provides macros for conditional compilation according to rustc compiler version, analogous to
#[cfg(...)]
and #[cfg_attr(...)]
.Forwarded from Awful Rust snippets for fun and profit
async uses a different drop checker, so rustc considers
issue
var
to be dropped after .await
playgroundissue
#prog #typescript #abnormalprogramming
https://github.com/ronami/HypeScript
(thanks @randomstuffilike)
https://github.com/ronami/HypeScript
(thanks @randomstuffilike)
GitHub
GitHub - ronami/HypeScript: 🐬 A simplified implementation of TypeScript's type system written in TypeScript's type system
🐬 A simplified implementation of TypeScript's type system written in TypeScript's type system - ronami/HypeScript
🤡2
#rust
The Ferrocene Language Specification is here!
Наконец-то опубликован первый черновик спеки для Rust
The Ferrocene Language Specification is here!
Наконец-то опубликован первый черновик спеки для Rust
👍8❤1
#prog #go
В стандартной библиотеке Go в пакете net/http есть тип Header, который, как следует из документации, является newtype-ом над
> ReverseProxy is an HTTP Handler that takes an incoming request and sends it to another server, proxying the response back to the client.
До 30 апреля 2020 года там также было следующее:
> ReverseProxy automatically sets the client IP as the value of the X-Forwarded-For header. If an X-Forwarded-For header already exists, the client IP is appended to the existing values.
Это поведение не для всех было удобным: "In our situation, the proxy should be transparent and invisible to the servers, so we'd like the proxy not to add any headers to the HTTP requests he forwards. Unfortunately, there is no option to disable the addition of the X-Forwarded-For header." В качестве решения предлагалось либо добавить явную опцию для подавления этого поведения, включённую по умолчанию, либо добавить хук, который бы редактировал заголовки непосредственно перед отправкой ответа.
К этому разработчики Go, как ни странно, прислушались, и в итоге исправили — правда, по своему, не реализовав ни тот, ни другой предложенный вариант. В изменении эксплуатировался тот факт, что слайс в Go является ссылочным типом (даром, что эта терминология в документации Go не используется): слайс может быть
> ReverseProxy by default sets the client IP as the value of the X-Forwarded-For header. If an X-Forwarded-For header already exists, the client IP is appended to the existing values. As a special case, if the header exists in the Request.Header map but has a nil value (such as when set by the Director func), the X-Forwarded-For header is not modified.
Это не очень изящное решение, хотя бы потому, что неконсистентно — в большинстве других мест пустые слайсы и
...Или нет. Метод ReverseProxy.ServeHTTP безусловно вызывает Request.Clone, внутри которого происходит вызов Header.Clone — ручной реализации глубокого копирования
В исправлении в начало тела этого цикла добавили
Для сравнения, у аналогичного по функционалу HeaderMap из крейта http, не смотря на более сложное устройство (и Амос объяснял, почему более сложное), вся реализация глубокого копирования сводится к #[derive(Clone)].
В стандартной библиотеке Go в пакете net/http есть тип Header, который, как следует из документации, является newtype-ом над
map[string][]string
. Значения этого типа хранят соответствие между заголовками в HTTP-запросе и связанной с ними информацией. Header
используется в net/http.Request, а тот, в свою очередь — в net/http/httputil.ReverseProxy. Как сказано в документации:> ReverseProxy is an HTTP Handler that takes an incoming request and sends it to another server, proxying the response back to the client.
До 30 апреля 2020 года там также было следующее:
> ReverseProxy automatically sets the client IP as the value of the X-Forwarded-For header. If an X-Forwarded-For header already exists, the client IP is appended to the existing values.
Это поведение не для всех было удобным: "In our situation, the proxy should be transparent and invisible to the servers, so we'd like the proxy not to add any headers to the HTTP requests he forwards. Unfortunately, there is no option to disable the addition of the X-Forwarded-For header." В качестве решения предлагалось либо добавить явную опцию для подавления этого поведения, включённую по умолчанию, либо добавить хук, который бы редактировал заголовки непосредственно перед отправкой ответа.
К этому разработчики Go, как ни странно, прислушались, и в итоге исправили — правда, по своему, не реализовав ни тот, ни другой предложенный вариант. В изменении эксплуатировался тот факт, что слайс в Go является ссылочным типом (даром, что эта терминология в документации Go не используется): слайс может быть
nil
, и это не то же самое, что и пустой слайс. После исправления новая документация ReverseProxy
гласила следующее:> ReverseProxy by default sets the client IP as the value of the X-Forwarded-For header. If an X-Forwarded-For header already exists, the client IP is appended to the existing values. As a special case, if the header exists in the Request.Header map but has a nil value (such as when set by the Director func), the X-Forwarded-For header is not modified.
Это не очень изящное решение, хотя бы потому, что неконсистентно — в большинстве других мест пустые слайсы и
nil
-слайсы ведут себя одинаково — и потому что заставляет пользователя ReverseProxy
вручную удалять заголовок. Но оно, по крайней мере, работало....Или нет. Метод ReverseProxy.ServeHTTP безусловно вызывает Request.Clone, внутри которого происходит вызов Header.Clone — ручной реализации глубокого копирования
Header
. Фрагмент кода оттуда:sv := make([]string, nv) // shared backing array for headers' values
h2 := make(Header, len(h))
for k, vv := range h {
n := copy(sv, vv)
h2[k] = sv[:n:n]
sv = sv[n:]
}
return h2
Встроенная функция copy ведёт себя одинаково и в том случае, когда vv
— пустой слайс, и в том случае, когда vv
— nil-слайс, и возвращает в обоих случаях 0. В следующей строчке мы видим безусловное присваивание h2[k] = sv[:n:n]
. Каким бы ни было значение n
, нарезка слайса никогда не возвращает nil-слайс. А это значит, что в возвращённой копии Header
nil-слайс будет замещён на пустой слайс, что и приводит к ошибочному поведению.В исправлении в начало тела этого цикла добавили
if
, который для случая, когда vv
является nil, присваивает соответствующему ключу в h2
значение nil
и переходит на следующую итерацию. Рядом с ним оставили комментарий: "Preserve nil values. ReverseProxy distinguishes between nil and zero-length header values".Для сравнения, у аналогичного по функционалу HeaderMap из крейта http, не смотря на более сложное устройство (и Амос объяснял, почему более сложное), вся реализация глубокого копирования сводится к #[derive(Clone)].
GitHub
net/http/httputil: do not add to empty X-Forwarded-For header in ReverseProxy · Issue #38079 · golang/go
What version of Go are you using (go version)? $ go version go version go1.13.8 linux/386 Does this issue reproduce with the latest release? Yes What operating system and processor architecture are...
❤1