pub auto trait Unpin { }
Expand description
Types that do not require any pinning guarantees.
For information on what “pinning” is, see the pin
module documentation.
Implementing the Unpin
trait for T
expresses the fact that T
is pinning-agnostic:
it shall not expose nor rely on any pinning guarantees. This, in turn, means that a
Pin
-wrapped pointer to such a type can feature a fully unrestricted API.
In other words, if T: Unpin
, a value of type T
will not be bound by the invariants
which pinning otherwise offers, even when “pinned” by a Pin<Ptr>
pointing at it.
When a value of type T
is pointed at by a Pin<Ptr>
, Pin
will not restrict access
to the pointee value like it normally would, thus allowing the user to do anything that they
normally could with a non-Pin
-wrapped Ptr
to that value.
The idea of this trait is to alleviate the reduced ergonomics of APIs that require the use
of Pin
for soundness for some types, but which also want to be used by other types that
don’t care about pinning. The prime example of such an API is Future::poll
. There are many
Future
types that don’t care about pinning. These futures can implement Unpin
and
therefore get around the pinning related restrictions in the API, while still allowing the
subset of Future
s which do require pinning to be implemented soundly.
For more discussion on the consequences of Unpin
within the wider scope of the pinning
system, see the section about Unpin
in the pin
module.
Unpin
has no consequence at all for non-pinned data. In particular, mem::replace
happily
moves !Unpin
data, which would be immovable when pinned (mem::replace
works for any
&mut T
, not just when T: Unpin
).
However, you cannot use mem::replace
on !Unpin
data which is pinned by being wrapped
inside a Pin<Ptr>
pointing at it. This is because you cannot (safely) use a
Pin<Ptr>
to get an &mut T
to its pointee value, which you would need to call
mem::replace
, and that is what makes this system work.
So this, for example, can only be done on types implementing Unpin
:
use std::mem;
use std::pin::Pin;
let mut string = "this".to_string();
let mut pinned_string = Pin::new(&mut string);
// We need a mutable reference to call `mem::replace`.
// We can obtain such a reference by (implicitly) invoking `Pin::deref_mut`,
// but that is only possible because `String` implements `Unpin`.
mem::replace(&mut *pinned_string, "other".to_string());
This trait is automatically implemented for almost every type. The compiler is free
to take the conservative stance of marking types as Unpin
so long as all of the types that
compose its fields are also Unpin
. This is because if a type implements Unpin
, then it
is unsound for that type’s implementation to rely on pinning-related guarantees for soundness,
even when viewed through a “pinning” pointer! It is the responsibility of the implementor of
a type that relies upon pinning for soundness to ensure that type is not marked as Unpin
by adding PhantomPinned
field. For more details, see the pin
module docs.