[−][src]Macro pin_project_lite::pin_project
A macro that creates a projection type covering all the fields of struct.
This macro creates a projection type according to the following rules:
- For the field that uses
#[pin]
attribute, makes the pinned reference to the field. - For the other fields, makes the unpinned reference to the field.
And the following methods are implemented on the original type:
fn project(self: Pin<&mut Self>) -> Projection<'_>; fn project_ref(self: Pin<&Self>) -> ProjectionRef<'_>;
By passing an attribute with the same name as the method to the macro, you can name the projection type returned from the method. This allows you to use pattern matching on the projected types.
pin_project! { #[project = EnumProj] enum Enum<T> { Variant { #[pin] field: T }, } } impl<T> Enum<T> { fn method(self: Pin<&mut Self>) { let this: EnumProj<'_, T> = self.project(); match this { EnumProj::Variant { field } => { let _: Pin<&mut T> = field; } } } }
The #[project]
(and #[project_ref]
) attribute must precede the other
attributes except for #[doc]
. For example, the following code will not be compiled:
pin_project! { /// documents (`#[doc]`) can be placed before `#[project]`. #[derive(Clone)] // <--- ERROR #[project = EnumProj] #[derive(Debug)] // <--- Ok enum Enum<T> { Variant { #[pin] field: T }, } }
Also, note that the projection types returned by project
and project_ref
have
an additional lifetime at the beginning of generics.
let this: EnumProj<'_, T> = self.project();
^^
The visibility of the projected types and projection methods is based on the
original type. However, if the visibility of the original type is pub
, the
visibility of the projected types and the projection methods is downgraded
to pub(crate)
.
Safety
pin_project!
macro guarantees safety in much the same way as pin-project crate.
Both are completely safe unless you write other unsafe code.
See pin-project crate for more details.
Examples
use pin_project_lite::pin_project; use std::pin::Pin; pin_project! { struct Struct<T, U> { #[pin] pinned: T, unpinned: U, } } impl<T, U> Struct<T, U> { fn method(self: Pin<&mut Self>) { let this = self.project(); let _: Pin<&mut T> = this.pinned; // Pinned reference to the field let _: &mut U = this.unpinned; // Normal reference to the field } }
To use pin_project!
on enums, you need to name the projection type
returned from the method.
use pin_project_lite::pin_project; use std::pin::Pin; pin_project! { #[project = EnumProj] enum Enum<T> { Struct { #[pin] field: T, }, Unit, } } impl<T> Enum<T> { fn method(self: Pin<&mut Self>) { match self.project() { EnumProj::Struct { field } => { let _: Pin<&mut T> = field; } EnumProj::Unit => {} } } }
If you want to call the project()
method multiple times or later use the
original Pin
type, it needs to use .as_mut()
to avoid
consuming the Pin
.
use pin_project_lite::pin_project; use std::pin::Pin; pin_project! { struct Struct<T> { #[pin] field: T, } } impl<T> Struct<T> { fn call_project_twice(mut self: Pin<&mut Self>) { // `project` consumes `self`, so reborrow the `Pin<&mut Self>` via `as_mut`. self.as_mut().project(); self.as_mut().project(); } }
!Unpin
If you want to ensure that Unpin
is not implemented, use #[pin]
attribute for a PhantomPinned
field.
use pin_project_lite::pin_project; use std::marker::PhantomPinned; pin_project! { struct Struct<T> { field: T, #[pin] // <------ This `#[pin]` is required to make `Struct` to `!Unpin`. _pin: PhantomPinned, } }
Note that using PhantomPinned
without #[pin]
attribute has no effect.