Ответ 1
Это все о структурном закреплении.
Во-первых, я буду использовать синтаксис P<T>
для обозначения чего-то вроде impl Deref<Target = T>
- некоторого (умного) указателя типа P
который Deref::deref
для T
Pin
только "относится" к/имеет смысл для таких (умных) указателей.
Допустим, у нас есть:
struct Wrapper<Field> {
field: Field,
}
Первоначальный вопрос
Можем ли мы получить
Pin<P<Field>>
изPin<P<Wrapper<Field>>>
, "проецируя" нашPin<P<_>>
изWrapper
на егоfield
?
Для этого требуется базовая проекция P<Wrapper<Field>> → P<Field>
, которая возможна только для:
-
общие ссылки (
P<T> = &T
). Это не очень интересный случай, учитывая, чтоPin<P<T>>
всегдаderef
кT
-
уникальные ссылки (
P<T> = &mut T
).
Я буду использовать синтаксис &[mut] T
для этого типа проекции.
Вопрос теперь становится:
Можем ли мы перейти от
Pin<&[mut] Wrapper<Field>>
кPin<&[mut] Field>
?
Вопрос, который может быть неясным из документации, заключается в том, что решение за создателем Wrapper
должен решать сам!
Существует два возможных варианта для автора библиотеки для каждого поля структуры.
Существует структурная проекция Pin
на это поле
Например, pin_utils::unsafe_pinned!
макрос используется для определения такой проекции (Pin<&mut Wrapper<Field>> → Pin<&mut Field>
).
Чтобы Pin
проецировался правильно:
-
вся структура должна реализовывать
Unpin
только тогда, когда все поля, для которых есть структурная проекцияPin
реализуютUnpin
.- никакая реализация не может использовать
unsafe
для перемещения таких полей изPin<&mut Wrapper<Field>>
(илиPin<&mut Self>
когдаSelf = Wrapper<Field>
). Например,Option::take()
запрещен.
- никакая реализация не может использовать
-
вся структура может реализовывать
Drop
только еслиDrop::drop
не перемещает ни одно из полей, для которых существует структурная проекция. -
структура не может быть
#[repr(packed)]
(следствие предыдущего элемента).
В вашем данном примере future::Map
это случай future
поля структуры Map
.
Там нет структурной проекции Pin
на это поле
Например, pin_utils::unsafe_unpinned!
макрос используется для определения такой проекции (Pin<&mut Wrapper<Field>> → &mut Field
).
В этом случае это поле не считается закрепленным с помощью Pin<&mut Wrapper<Field>>
.
-
не имеет значения
Field
Unpin
или нет.- реализациям разрешено использовать
unsafe
для перемещения таких полей изPin<&mut Wrapper<Field>>
. Например,Option::take()
разрешен.
- реализациям разрешено использовать
-
Drop::drop
также разрешено перемещать такие поля,
В приведенном вами примере future::Map
это случай поля f
структуры Map
.
Пример обоих типов проекции
impl<Fut, F> Map<Fut, F> {
unsafe_pinned!(future: Fut); // pin projection -----+
unsafe_unpinned!(f: Option<F>); // not pinned --+ |
// | |
// ... | |
// | |
fn poll (mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
// | |
match self.as_mut().future().poll(cx) { // <----+ required here
Poll::Pending => Poll::Pending, // |
Poll::Ready(output) => { // |
let f = self.f().take() // <--------+ allows this