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::derefs 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>>alwaysderefs 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
Pinprojection to that field;
(for instance, when the::pin_utils::unsafe_pinned!macro is used to define such projection)Then, for the
Pinprojection to be sound:-
the whole struct must only implement
Unpinwhen all the fields for which there is a structuralPinprojection implementUnpin,- Thus, no implementation is allowed to use
unsafeto 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
DropifDrop::dropdoes 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::Mapexample, this is the case of thefuturefield of theMapstruct.
-
-
or there is no
Pinprojection to that field;In that case, that field is not considered pinned! (by a
Pin<&mut Wrapper<Field>>)-
thus whether
FieldisUnpinor not, does not matter;- implementations are allowed to use
unsafeto 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 Fieldprojection. -
Drop::dropis also allowed to move such fields, -
In your given
future::Mapexample, this is the case of theffield of theMapstruct.
-