macro_rules! pin_init { ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }) => { ... }; }
Expand description
Construct an in-place, pinned initializer for struct
s.
This macro defaults the error to Infallible
. If you need Error
, then use
try_pin_init!
.
The syntax is almost identical to that of a normal struct
initializer:
#[pin_data]
struct Foo {
a: usize,
b: Bar,
}
#[pin_data]
struct Bar {
x: u32,
}
let a = 42;
let initializer = pin_init!(Foo {
a,
b: Bar {
x: 64,
},
});
Arbitrary Rust expressions can be used to set the value of a variable.
The fields are initialized in the order that they appear in the initializer. So it is possible to read already initialized fields using raw pointers.
IMPORTANT: You are not allowed to create references to fields of the struct inside of the initializer.
Init-functions
When working with this API it is often desired to let others construct your types without
giving access to all fields. This is where you would normally write a plain function new
that would return a new instance of your type. With this API that is also possible.
However, there are a few extra things to keep in mind.
To create an initializer function, simply declare it like this:
impl Foo {
fn new() -> impl PinInit<Self> {
pin_init!(Self {
a: 42,
b: Bar {
x: 64,
},
})
}
}
Users of Foo
can now create it like this:
let foo = Box::pin_init(Foo::new());
They can also easily embed it into their own struct
s:
#[pin_data]
struct FooContainer {
#[pin]
foo1: Foo,
#[pin]
foo2: Foo,
other: u32,
}
impl FooContainer {
fn new(other: u32) -> impl PinInit<Self> {
pin_init!(Self {
foo1 <- Foo::new(),
foo2 <- Foo::new(),
other,
})
}
}
Here we see that when using pin_init!
with PinInit
, one needs to write <-
instead of :
.
This signifies that the given field is initialized in-place. As with struct
initializers, just
writing the field (in this case other
) without :
or <-
means other: other,
.
Syntax
As already mentioned in the examples above, inside of pin_init!
a struct
initializer with
the following modifications is expected:
- Fields that you want to initialize in-place have to use
<-
instead of:
. - In front of the initializer you can write
&this in
to have access to aNonNull<Self>
pointer namedthis
inside of the initializer. - Using struct update syntax one can place
..Zeroable::zeroed()
at the very end of the struct, this initializes every field with 0 and then runs all initializers specified in the body. This can only be done ifZeroable
is implemented for the struct.
For instance:
#[pin_data]
#[derive(Zeroable)]
struct Buf {
// `ptr` points into `buf`.
ptr: *mut u8,
buf: [u8; 64],
#[pin]
pin: PhantomPinned,
}
pin_init!(&this in Buf {
buf: [0; 64],
ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() },
pin: PhantomPinned,
});
pin_init!(Buf {
buf: [1; 64],
..Zeroable::zeroed()
});