macro_rules! pin_project {
(
$(#[$attrs:meta])*
pub struct $ident:ident
$(<
$( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)?
$( $generics:ident $(: $generics_bound:path)? $(: ?$generics_unsized_bound:path)? $(: $generics_lifetime_bound:lifetime)? $(= $generics_default:ty)? ),* $(,)?
>)?
$(where
$($where_clause_ty:ty : $where_clause_bound:path),* $(,)?
)?
{
$(
$(#[$pin:ident])?
$field_vis:vis $field:ident: $field_ty:ty
),+ $(,)?
}
) => { ... };
(
$(#[$attrs:meta])*
$vis:vis struct $ident:ident
$(<
$( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)?
$( $generics:ident $(: $generics_bound:path)? $(: ?$generics_unsized_bound:path)? $(: $generics_lifetime_bound:lifetime)? $(= $generics_default:ty)? ),* $(,)?
>)?
$(where
$($where_clause_ty:ty : $where_clause_bound:path),* $(,)?
)?
{
$(
$(#[$pin:ident])?
$field_vis:vis $field:ident: $field_ty:ty
),+ $(,)?
}
) => { ... };
(@internal ($proj_vis:vis)
$(#[$attrs:meta])*
$vis:vis struct $ident:ident
$(<
$( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),*
$( $generics:ident $(: $generics_bound:path)? $(: ?$generics_unsized_bound:path)? $(: $generics_lifetime_bound:lifetime)? $(= $generics_default:ty)? ),*
>)?
$(where
$($where_clause_ty:ty : $where_clause_bound:path),*
)?
{
$(
$(#[$pin:ident])?
$field_vis:vis $field:ident: $field_ty:ty
),+
}
) => { ... };
(@make_unpin_bound
#[pin]
$field_ty:ty
) => { ... };
(@make_unpin_bound
$field_ty:ty
) => { ... };
(@make_unsafe_field_proj
$this:ident;
#[pin]
$field:ident;
$($mut:ident)?
) => { ... };
(@make_unsafe_field_proj
$this:ident;
$field:ident;
$($mut:ident)?
) => { ... };
(@make_proj_field
#[pin]
$field_ty:ty;
$($mut:ident)?
) => { ... };
(@make_proj_field
$field_ty:ty;
$($mut:ident)?
) => { ... };
}
A macro that creates a projection struct covering all the fields.
This macro creates a projection struct 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.
The following methods are implemented on the original type:
fn project(self: Pin<&mut Self>) -> Projection<'_>;
fn project_ref(self: Pin<&Self>) -> ProjectionRef<'_>;
The visibility of the projected type and projection method is based on the
original type. However, if the visibility of the original type is pub
,
the visibility of the projected type and the projection method is pub(crate)
.
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
.
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.
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 foo(self: Pin<&mut Self>) {
let this = self.project();
let _: Pin<&mut T> = this.pinned;
let _: &mut U = this.unpinned;
}
}
Note that borrowing the field where #[pin]
attribute is used multiple
times requires using .as_mut()
to avoid
consuming the Pin
.