1.33.0[][src]Module boolean_enums::lstd::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-referential structs, since moving an object with pointers to itself will invalidate them, which could cause undefined behavior.

By default, all types in Rust are movable. Rust allows passing all types by-value, and common smart-pointer types such as Box, Rc, and &mut allow replacing and moving the values they contain. In order to prevent objects from moving, they must be pinned by wrapping a pointer to the data in the Pin type. Doing this prohibits moving the value behind the pointer. For example, Pin<Box<T>> functions much like a regular Box<T>, but doesn't allow moving T. The pointer value itself (the Box) can still be moved, but the value behind it cannot.

Since data can be moved out of &mut and Box with functions such as swap, changing the location of the underlying data, Pin prohibits accessing the underlying pointer type (the &mut or Box) directly, and provides its own set of APIs for accessing and using the value. Pin also guarantees that no other functions will move the pointed-to value. This allows for the creation of self-references and other special behaviors that are only possible for unmovable values.

However, these restrictions are usually not necessary. Many types are always freely movable. These types implement the Unpin auto-trait, which nullifies the effect of Pin. For T: Unpin, Pin<Box<T>> and Box<T> function identically, as do Pin<&mut T> and &mut T.

Note that pinning and Unpin only affect the pointed-to type. For example, whether or not Box<T> is Unpin has no affect on the behavior of Pin<Box<T>>. Similarly, Pin<Box<T>> and Pin<&mut T> are always Unpin themselves, even though the T underneath them isn't, because the pointers in Pin<Box<_>> and Pin<&mut _> are always freely movable, even if the data they point to isn't.

Examples

use std::pin::Pin;
use std::marker::PhantomPinned;
use std::ptr::NonNull;

// This is a self-referential 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: PhantomPinned,
}

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: PhantomPinned,
        };
        let mut boxed = Box::pin(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_unchecked_mut(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);

Structs

Pin

A pinned pointer.