That is what structural pinning is about:
First, I will note P<T>
something like impl Deref<Target = T>
, that is, some (smart) pointer type P
that Deref::deref
s to a T
(Pin
only "applies" to / make sense on such (smart) pointers).
Let's say we have:
struct Wrapper<Field> {
field: Field,
}
Now, the question is, whether we can get a Pin<P< Field >>
from a Pin<P< Wrapper<Field> >>
, by "projecting" our Pin<P<_>>
from the Wrapper
to its field
.
This already requires the basic projection P<Wrapper<Field>> -> P<Field>
, which is only even possible for
-
shared references:
P<T> = &T
(this is not a very interesting case given thatPin<P<T>>
alwaysderef
s toT
) -
unique references:
P<T> = &mut T
.
I will note this &[mut] T
So, the question is:
Can we go from
Pin<&[mut] Wrapper<Field>>
toPin<&[mut] Field>
?
The point that may still be unclear in the documentation is the following: it is up to the creator of Wrapper
to decide!
So there are two possible choices for the library author, regarding each one of the struct fields:
-
either there is a structural
Pin
projection to that field;
(for instance, when the::pin_utils::unsafe_pinned!
macro is used to define such projection)Then, for the
Pin
projection to be sound:-
the whole struct must only implement
Unpin
when all the fields for which there is a structuralPin
projection implementUnpin
,- Thus, no implementation is allowed to use
unsafe
to move such fields out of aPin<&mut Wrapper<Field>>
(orPin<&mut Self>
whenSelf = Wrapper<Field>
); for instance,Option::take()
is forbidden.
- Thus, no implementation is allowed to use
-
the whole struct may only implement
Drop
ifDrop::drop
does not move any of the fields for which there is a structural projection, -
the struct cannot be
#[repr(packed)]
(a corollary of the previous item). -
In your given
future::Map
example, this is the case of thefuture
field of theMap
struct.
-
-
or there is no
Pin
projection to that field;In that case, that field is not considered pinned! (by a
Pin<&mut Wrapper<Field>>
)-
thus whether
Field
isUnpin
or not, does not matter;- implementations are allowed to use
unsafe
to move such fields out of aPin<&mut Wrapper<Field>>
; for instance,Option::take()
is allowed.
- implementations are allowed to use
-
and
::pin_utils::unsafe_unpinned!
is safe to use to define aPin<&mut Wrapper<Field>> -> &mut Field
projection. -
Drop::drop
is also allowed to move such fields, -
In your given
future::Map
example, this is the case of thef
field of theMap
struct.
-