Crate pinned_init
source · [−]Expand description
Library to safely and fallibly initialize pinned structs in-place.
It also allows in-place initialization of big structs that would otherwise produce a stack overflow.
The problem
When writing self referential data structures in Rust, one runs into the issue of initializing them. For example we will create an intrusive, doubly linked, circular list in Rust:
use core::{ptr::NonNull, marker::PhantomPinned};
use pinned_init::*;
pin_data! {
pub struct ListHead {
next: NonNull<ListHead>,
prev: NonNull<ListHead>,
// ListHead is `!Unpin` because `next.prev = self`
#pin
_pin: PhantomPinned,
}
}
But now, how would one go about creating a ListHead
? A valid initial state of
a singular ListHead is, with next
and prev
pointing to self
. But in Rust
we cannot get a hold of self
until we have selected a value for next
!
This library
This library provides the means to achieve this safely:
use core::{ptr::NonNull, marker::PhantomPinned};
use pinned_init::*;
pin_data! {
pub struct ListHead {
next: NonNull<ListHead>,
prev: NonNull<ListHead>,
// ListHead is `!Unpin` because `next.prev = self`
#pin
_pin: PhantomPinned,
}
}
impl ListHead {
pub fn new_in_place() -> impl PinInit<ListHead> {
pin_init!(&this in ListHead {
next: this,
prev: this,
_pin: PhantomPinned,
})
}
}
Insead of writing new() -> Self
we write new_in_place() -> impl PinInit<Self>
. This function now
returns an in-place initializer. The pin_init!
macro used to create this initializer has the same
syntax as a struct initializer. You will need to specify every field and can use arbitrary
expressions. When an expression evaluates to an in-place initializer from this library, it is used
to initialize the value in-place.
Macros
Structs
Enums
Traits
T
.T
.