#pin #owned #move #rvalue

nightly no-std owned-pin

A wrapper that both owns and pins data in memory

10 releases (stable)

1.3.3 Dec 2, 2023
1.3.1 Dec 1, 2023
1.2.0 Nov 30, 2023
0.2.0 Nov 30, 2023
0.1.1 Nov 30, 2023

#211 in Memory management

Download history 145/week @ 2024-02-19 35/week @ 2024-02-26 4/week @ 2024-03-11 69/week @ 2024-04-01

73 downloads per month

MIT/Apache

66KB
1K SLoC

Owned Pin

Cargo Documentation License

This crate deals with data that is owned by some entity but (maybe) immovable in memory. It is inspired by R-value references in C++.

See the documentation for more information.

Examples

With Pin<P> only, we cannot guarantee the move semantics of the value.

use core::pin::{Pin, pin};
use core::marker::PhantomPinned;

fn try_to_take_the_ownership_of<T>(pinned: Pin<&mut T>) {}

let mut value = pin!(PhantomPinned);
// The caller can reborrow the value...
try_to_take_the_ownership_of(value.as_mut());
// ... so the same pinned data can be used twice,
// thus unable to guarantee the move semantics.
try_to_take_the_ownership_of(value.as_mut());

In practice, this is because there is no such smart pointer that owns data by holding a unique reference to some other location on the stack.

Thus, we introduce the OnStack<T> smart pointer and an alias of OPin<T> = Pin<OnStack<T>>, which both "own" and "pin" the data on the stack, enabling the example above to work as desired:

use owned_pin::{OPin, opin};
use core::marker::PhantomPinned;

fn take_the_ownership_of<T>(owned_and_pinned: OPin<T>) {}

let value = opin!(PhantomPinned);
// The `as_mut` method of `OPin` actually
// returns a `Pin<&mut T>`...
take_the_ownership_of(value);
// ... so the value itself cannot be used again.
// The line below causes rustc to emit `E0382`.
// take_the_ownership_of(value);

With data that implements Unpin, we can even move it out from the wrapper safe and sound:

use owned_pin::{opin, unpin};

// Pins the value onto the stack.
let pinned = opin!(String::from("Hello!"));
// Retrieves back the data because `String` is `Unpin`.
let string: String = unpin(pinned);

License

MIT OR Apache-2.0

Dependencies

~0.5–1MB
~20K SLoC