[−][src]Module std::pin
Types which pin data to its location in memory
It is sometimes useful to have objects that are guaranteed to not move, in the sense that their placement in memory does not change, and can thus be relied upon.
A prime example of such a scenario would be building self-referencial structs, since moving an object with pointers to itself will invalidate them, which could cause undefined behavior.
In order to prevent objects from moving, they must be pinned
by wrapping a pointer to the data in the Pin
type. A pointer wrapped
in a Pin
is otherwise equivalent to its normal version, e.g. Pin<Box<T>>
and Box<T>
work the same way except that the first is pinning the value
of T
in place.
First of all, these are pointer types because pinned data mustn't be passed around by value
(that would change its location in memory).
Secondly, since data can be moved out of &mut
and Box
with functions such as swap
,
which causes their contents to swap places in memory,
we need dedicated types that prohibit such operations.
However, these restrictions are usually not necessary,
so most types implement the Unpin
auto-trait,
which indicates that the type can be moved out safely.
Doing so removes the limitations of pinning types,
making them the same as their non-pinning counterparts.
Examples
#![feature(pin)] use std::pin::Pin; use std::marker::Pinned; use std::ptr::NonNull; // This is a self referencial struct since the slice field points to the data field. // We cannot inform the compiler about that with a normal reference, // since this pattern cannot be described with the usual borrowing rules. // Instead we use a raw pointer, though one which is known to not be null, // since we know it's pointing at the string. struct Unmovable { data: String, slice: NonNull<String>, _pin: Pinned, } impl Unmovable { // To ensure the data doesn't move when the function returns, // we place it in the heap where it will stay for the lifetime of the object, // and the only way to access it would be through a pointer to it. fn new(data: String) -> Pin<Box<Self>> { let res = Unmovable { data, // we only create the pointer once the data is in place // otherwise it will have already moved before we even started slice: NonNull::dangling(), _pin: Pinned, }; let mut boxed = Box::pinned(res); let slice = NonNull::from(&boxed.data); // we know this is safe because modifying a field doesn't move the whole struct unsafe { let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed); Pin::get_mut_unchecked(mut_ref).slice = slice; } boxed } } let unmoved = Unmovable::new("hello".to_string()); // The pointer should point to the correct location, // so long as the struct hasn't moved. // Meanwhile, we are free to move the pointer around. let mut still_unmoved = unmoved; assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data)); // Since our type doesn't implement Unpin, this will fail to compile: // let new_unmoved = Unmovable::new("world".to_string()); // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);Run
Structs
Pin |
[ Experimental ] A pinned pointer. |
Traits
Unpin |
[ Experimental ] Types which can be safely moved after being pinned. |