| Crates.io | pin-macros |
| lib.rs | pin-macros |
| version | 1.0.0-a.2 |
| created_at | 2024-08-28 18:36:39.674608+00 |
| updated_at | 2024-08-31 20:02:24.514042+00 |
| description | This library is primarly used to simplify the proccess of working with self-referencial structures. |
| homepage | |
| repository | https://github.com/retueZe/pin-macros |
| max_upload_size | |
| id | 1355011 |
| size | 12,124 |
pin-macrosThis library is primarly used to simplify the proccess of working with self-referencial structures.
To read this document further, you should have:
std::pin::Pin;std::pin::Unpin;std::mem::MaybeUninit;std::marker::PhantomPinned;use std::{pin::Pin, marker::PhantomPinned};
use pin_macros::{pin_init, pin_new};
struct SelfReferential<'a> {
self_ref: Pin<&'a mut SelfReferential<'a>>,
val: u32,
marker: PhantomPinned,
}
impl<'a> SelfReferential<'a> {
// this is a syntaxic sugar for
// `pub fn init(ptr: Pin<&'a mut MaybeUninit<Self>>, val: u32) -> Pin<&'a mut Self> { ... }`
pin_init!(pub fn init<'a>(this, val: u32) {
// macro available only inside `pin_init!` scope
// the structure is immovable, it is safe to use a mutable self-reference
// since it's garanteed that we have only one mutable ref to this value
// and it doesn't go outside the structure's private scope
this.self_ref = pin_init_clone!();
this.val = val;
this.marker = PhantomPinned::default();
});
}
fn main() {
// allocates an immovable value on stack and stores
// a `Pin<&mut SelfReferencial>` in `self_ref`
pin_new!(mut self_ref: SelfReferential = init(123));
}
In this section, by Self, with a lifetime 'a, we will mean the immovable type we are working with.
pin_new!This macro allocates an immovable value on the stack, using MaybeUninit::<Self>::uninit(), and then initializes it using the Self::init method, storing the initialized Pin<&mut Self> pointer in a variable. The variable may be mutable or immutable, depending on the passed tokens.
fn main() {
pin_new!(val: T = init(...));
// OR
pin_new!(mut val: T = init(...));
}
pin_init!This macro defines an initialization method in an impl. It consumes the following tokens:
pub;'a);&'a mut Self pointer;It is basically syntactic sugar:
pin_init!(pub fn init<'a>(this, arg1: u32, arg2: i32) {
this.arg1 = arg1;
this.arg2 = arg2;
})
// CONVERTED TO
pub fn init(__ptr: Pin<&'a mut MaybeUninit<Self>>, arg1: u32, arg2: i32) -> Pin<&'a mut Self> {
// defines `pin_init_xxx!` macros
let this: &'a mut Self = ...;
this.arg1 = arg1;
this.arg2 = arg2;
unsafe { Pin::new_unchecked(this) }
}
pin_init_clone!This macro returns a pointer to the already initialized value from the future (Pin<&'a mut T>). Since the value is immovable, we can know the addresses of the value and all its fields before the initialization code runs. While the results of pin_init_clone! calls are owned by Self fields, and the fields are not exposed outside of Self's private scope, it is safe to have multiple mutable references inside.
pin_init!(... {
this.pointer_to_itself = pin_init_clone!();
})
pin_init_field!This macro returns a Pin<&'a mut MaybeUninit<F>> pointer, where F is a field value type of Self. This is used when Self owns another immovable value, and we need to initialize it.
struct Outer<'a> {
inner: Inner<'a>,
...
}
impl<'a> Outer<'a> {
pin_init!(... {
Inner::init(pin_init_field!(inner: Inner), ...);
})
}
pin_field_init!This macro is used to initialize Option<F> during the 'a lifetime but outside the Self::init call lifetime, where F is a field value type of Self. It has two forms: one for owned immovable values and another for anything else.
// initialization of owned immovable value
pub fn init_during_runtime(self: Pin<&'a mut Self>, ...) {
// under the hood, we fill the option with `Some(MaybeUninit::<F>::uninit().assume_init())`,
// and initialize the value
pin_field_init!(Inner: init(self.inner, ...));
}
// initialization of `Option<(&'a mut F1, &'a mut F2)>`
pub fn init_during_runtime(self: Pin<&'a mut Self>) {
// we obtain mutable refs to `field1` and `field2`, and then accumulate them in the `dest_field`
pin_field_init!(self: |field1, field2 => dest_field| (&mut field1, &mut field2))
}
field_pin! & field_unpin!These macros are used as wrappers for self.field calls. Since our self is always wrapped in Pin, we cannot simply access a field value. The field_pin! macro is used to create private methods that obtain Pin<&mut F>, while field_unpin! is used for &mut F, where F is a field value type of Self. Clearly, field_pin! should be used for immovable values, and field_unpin! should be used for movable values.