// SPDX-License-Identifier: Apache-2.0 OR MIT use proc_macro2::TokenStream;use quote::{format_ident, quote};use syn::{ parse::{End, Nothing, Parse}, parse_quote, parse_quote_spanned, spanned::Spanned, visit_mut::VisitMut, Attribute, Field, Generics, Ident, Item, PathSegment, Type, TypePath, Visibility, WhereClause,}; use crate::diagnostics::{DiagCtxt, ErrorGuaranteed}; pub(crate) mod kw { syn::custom_keyword!(PinnedDrop);} pub(crate) enum Args { Nothing(Nothing), #[allow(dead_code)] PinnedDrop(kw::PinnedDrop),} impl Parse for Args { fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { let lh = input.lookahead1(); if lh.peek(End) { input.parse().map(Self::Nothing) } else if lh.peek(kw::PinnedDrop) { input.parse().map(Self::PinnedDrop) } else { Err(lh.error()) } }} struct FieldInfo<'a> { field: &'a Field, pinned: bool, cfg_attrs: Vec<&'a Attribute>,} pub(crate) fn pin_data( args: Args, input: Item, dcx: &mut DiagCtxt,) -> Result<TokenStream, ErrorGuaranteed> { let mut struct_ = match input { Item::Struct(struct_) => struct_, Item::Enum(enum_) => { return Err(dcx.error( enum_.enum_token, "`#[pin_data]` only supports structs for now", )); } Item::Union(union) => { return Err(dcx.error( union.union_token, "`#[pin_data]` only supports structs for now", )); } rest => { return Err(dcx.error( rest, "`#[pin_data]` can only be applied to struct, enum and union definitions", )); } }; // The generics might contain the `Self` type. Since this macro will define a new type with the // same generics and bounds, this poses a problem: `Self` will refer to the new type as opposed // to this struct definition. Therefore we have to replace `Self` with the concrete name. let mut replacer = { let name = &struct_.ident; let (_, ty_generics, _) = struct_.generics.split_for_impl(); SelfReplacer(parse_quote!(#name #ty_generics)) }; replacer.visit_generics_mut(&mut struct_.generics); replacer.visit_fields_mut(&mut struct_.fields); let fields: Vec<FieldInfo<'_>> = struct_ .fields .iter_mut() .map(|field| { let len = field.attrs.len(); field.attrs.retain(|a| !a.path().is_ident("pin")); let pinned = len != field.attrs.len(); let cfg_attrs = field .attrs .iter() .filter(|a| a.path().is_ident("cfg")) .collect(); FieldInfo { field: &*field, pinned, cfg_attrs, } }) .collect(); for field in &fields { let ident = field.field.ident.as_ref().unwrap(); if !field.pinned && is_phantom_pinned(&field.field.ty) { dcx.warn( field.field, format!( "The field `{ident}` of type `PhantomPinned` only has an effect \ if it has the `#[pin]` attribute", ), ); } } let unpin_impl = generate_unpin_impl(&struct_.ident, &struct_.generics, &fields); let drop_impl = generate_drop_impl(&struct_.ident, &struct_.generics, args); let projections = generate_projections(&struct_.vis, &struct_.ident, &struct_.generics, &fields); let the_pin_data = generate_the_pin_data(&struct_.vis, &struct_.ident, &struct_.generics, &fields); Ok(quote! { #struct_ #projections // We put the rest into this const item, because it then will not be accessible to anything // outside. const _: () = { #the_pin_data #unpin_impl #drop_impl }; })} fn is_phantom_pinned(ty: &Type) -> bool { match ty { Type::Path(TypePath { qself: None, path }) => { // Cannot possibly refer to `PhantomPinned` (except alias, but that's on the user). if path.segments.len() > 3 { return false; } // If there is a `::`, then the path needs to be `::core::marker::PhantomPinned` or // `::std::marker::PhantomPinned`. if path.leading_colon.is_some() && path.segments.len() != 3 { return false; } let expected: Vec<&[&str]> = vec![&["PhantomPinned"], &["marker"], &["core", "std"]]; for (actual, expected) in path.segments.iter().rev().zip(expected) { if !actual.arguments.is_empty() || expected.iter().all(|e| actual.ident != e) { return false; } } true } _ => false, }} fn generate_unpin_impl( ident: &Ident, generics: &Generics, fields: &[FieldInfo<'_>],) -> TokenStream { let (_, ty_generics, _) = generics.split_for_impl(); let mut generics_with_pin_lt = generics.clone(); generics_with_pin_lt.params.insert(0, parse_quote!('__pin)); generics_with_pin_lt.make_where_clause(); let ( impl_generics_with_pin_lt, ty_generics_with_pin_lt, Some(WhereClause { where_token, predicates, }), ) = generics_with_pin_lt.split_for_impl() else { unreachable!() }; let pinned_fields = fields.iter().filter(|f| f.pinned).map(|f| { let ident = f.field.ident.as_ref().unwrap(); let ty = &f.field.ty; let cfg_attrs = &f.cfg_attrs; quote!( #(#cfg_attrs)* #ident: #ty ) }); quote! { // This struct will be used for the unpin analysis. It is needed, because only structurally // pinned fields are relevant whether the struct should implement `Unpin`. #[allow( dead_code, // The fields below are never used. non_snake_case // The warning will be emitted on the struct definition. )] struct __Unpin #generics_with_pin_lt #where_token #predicates { __phantom_pin: ::pin_init::__internal::PhantomInvariantLifetime<'__pin>, __phantom: ::pin_init::__internal::PhantomInvariant<#ident #ty_generics>, #(#pinned_fields),* } #[doc(hidden)] impl #impl_generics_with_pin_lt ::core::marker::Unpin for #ident #ty_generics #where_token __Unpin #ty_generics_with_pin_lt: ::core::marker::Unpin, #predicates {} }} fn generate_drop_impl(ident: &Ident, generics: &Generics, args: Args) -> TokenStream { let (impl_generics, ty_generics, whr) = generics.split_for_impl(); let has_pinned_drop = matches!(args, Args::PinnedDrop(_)); // We need to disallow normal `Drop` implementation, the exact behavior depends on whether // `PinnedDrop` was specified in `args`. if has_pinned_drop { // When `PinnedDrop` was specified we just implement `Drop` and delegate. quote! { impl #impl_generics ::core::ops::Drop for #ident #ty_generics #whr { fn drop(&mut self) { // SAFETY: Since this is a destructor, `self` will not move after this function // terminates, since it is inaccessible. let pinned = unsafe { ::core::pin::Pin::new_unchecked(self) }; // SAFETY: Since this is a drop function, we can create this token to call the // pinned destructor of this type. let token = unsafe { ::pin_init::__internal::OnlyCallFromDrop::new() }; ::pin_init::PinnedDrop::drop(pinned, token); } } } } else { // When no `PinnedDrop` was specified, then we have to prevent implementing drop. quote! { // We prevent this by creating a trait that will be implemented for all types implementing // `Drop`. Additionally we will implement this trait for the struct leading to a conflict, // if it also implements `Drop` trait MustNotImplDrop {} #[expect(drop_bounds)] impl<T: ::core::ops::Drop + ?::core::marker::Sized> MustNotImplDrop for T {} impl #impl_generics MustNotImplDrop for #ident #ty_generics #whr {} // We also take care to prevent users from writing a useless `PinnedDrop` implementation. // They might implement `PinnedDrop` correctly for the struct, but forget to give // `PinnedDrop` as the parameter to `#[pin_data]`. #[expect(non_camel_case_types)] trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} impl<T: ::pin_init::PinnedDrop + ?::core::marker::Sized> UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} impl #impl_generics UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for #ident #ty_generics #whr {} } }} fn generate_projections( vis: &Visibility, ident: &Ident, generics: &Generics, fields: &[FieldInfo<'_>],) -> TokenStream { let (impl_generics, ty_generics, _) = generics.split_for_impl(); let mut generics_with_pin_lt = generics.clone(); generics_with_pin_lt.params.insert(0, parse_quote!('__pin)); let (_, ty_generics_with_pin_lt, whr) = generics_with_pin_lt.split_for_impl(); let projection = format_ident!("{ident}Projection"); let this = format_ident!("this"); let (fields_decl, fields_proj): (Vec<_>, Vec<_>) = fields .iter() .map(|field| { let Field { vis, ident, ty, .. } = &field.field; let cfg_attrs = &field.cfg_attrs; let ident = ident .as_ref() .expect("only structs with named fields are supported"); if field.pinned { ( quote!( #(#cfg_attrs)* #vis #ident: ::core::pin::Pin<&'__pin mut #ty>, ), quote!( #(#cfg_attrs)* // SAFETY: this field is structurally pinned. #ident: unsafe { ::core::pin::Pin::new_unchecked(&mut #this.#ident) }, ), ) } else { ( quote!( #(#cfg_attrs)* #vis #ident: &'__pin mut #ty, ), quote!( #(#cfg_attrs)* #ident: &mut #this.#ident, ), ) } }) .collect(); let structurally_pinned_fields_docs = fields .iter() .filter(|f| f.pinned) .map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap())); let not_structurally_pinned_fields_docs = fields .iter() .filter(|f| !f.pinned) .map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap())); let docs = format!(" Pin-projections of [`{ident}`]"); quote! { #[doc = #docs] // Allow `non_snake_case` since the same warning will be emitted on // the struct definition. #[allow(dead_code, non_snake_case)] #[doc(hidden)] #vis struct #projection #generics_with_pin_lt #whr { #(#fields_decl)* ___pin_phantom_data: ::core::marker::PhantomData<&'__pin mut ()>, } impl #impl_generics #ident #ty_generics #whr { /// Pin-projects all fields of `Self`. /// /// These fields are structurally pinned: #(#[doc = #structurally_pinned_fields_docs])* /// /// These fields are **not** structurally pinned: #(#[doc = #not_structurally_pinned_fields_docs])* #[inline] #vis fn project<'__pin>( self: ::core::pin::Pin<&'__pin mut Self>, ) -> #projection #ty_generics_with_pin_lt { // SAFETY: we only give access to `&mut` for fields not structurally pinned. let #this = unsafe { ::core::pin::Pin::get_unchecked_mut(self) }; #projection { #(#fields_proj)* ___pin_phantom_data: ::core::marker::PhantomData, } } } }} fn generate_the_pin_data( vis: &Visibility, struct_name: &Ident, generics: &Generics, fields: &[FieldInfo<'_>],) -> TokenStream { let (impl_generics, ty_generics, whr) = generics.split_for_impl(); // For every field, we create an initializing projection function according to its projection // type. If a field is structurally pinned, we create a `Slot` with `Pinned` which must be // initialized via `PinInit`; if it is not structurally pinned, then we create a `Slot` with // `Unpinned` which allows initialization via `Init`. let field_accessors = fields .iter() .map(|f| { let Field { vis, ident, ty, .. } = f.field; let cfg_attrs = &f.cfg_attrs; let field_name = ident .as_ref() .expect("only structs with named fields are supported"); let pin_marker = if f.pinned { quote!(Pinned) } else { quote!(Unpinned) }; quote! { /// # Safety /// /// - `slot` is valid and properly aligned. /// - `(*slot).#field_name` is properly aligned. /// - `(*slot).#field_name` points to uninitialized and exclusively accessed /// memory. #(#cfg_attrs)* // Allow `non_snake_case` since the same warning will be emitted on // the struct definition. #[allow(non_snake_case)] #[inline(always)] #vis unsafe fn #field_name( self, slot: *mut #struct_name #ty_generics, ) -> ::pin_init::__internal::Slot<::pin_init::__internal::#pin_marker, #ty> { // SAFETY: // - If `#pin_marker` is `Pinned`, the corresponding field is structurally // pinned. // - Other safety requirements follows the safety requirement. unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).#field_name) } } } }) .collect::<TokenStream>(); quote! { // We declare this struct which will host all of the projection function for our type. It // will be invariant over all generic parameters which are inherited from the struct. #[doc(hidden)] #vis struct __ThePinData #generics #whr { __phantom: ::pin_init::__internal::PhantomInvariant<#struct_name #ty_generics>, } impl #impl_generics ::core::clone::Clone for __ThePinData #ty_generics #whr { fn clone(&self) -> Self { *self } } impl #impl_generics ::core::marker::Copy for __ThePinData #ty_generics #whr {} #[allow(dead_code)] // Some functions might never be used and private. #[expect(clippy::missing_safety_doc)] impl #impl_generics __ThePinData #ty_generics #whr { /// Type inference helper function. #[inline(always)] #vis fn __make_closure<__F, __E>(self, f: __F) -> __F where __F: FnOnce(*mut #struct_name #ty_generics) -> ::core::result::Result<::pin_init::__internal::InitOk, __E>, { f } #field_accessors } // SAFETY: We have added the correct projection functions above to `__ThePinData` and // we also use the least restrictive generics possible. unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #struct_name #ty_generics #whr { type PinData = __ThePinData #ty_generics; unsafe fn __pin_data() -> Self::PinData { __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() } } } }} struct SelfReplacer(PathSegment); impl VisitMut for SelfReplacer { fn visit_path_mut(&mut self, i: &mut syn::Path) { if i.is_ident("Self") { let span = i.span(); let seg = &self.0; *i = parse_quote_spanned!(span=> #seg); } else { syn::visit_mut::visit_path_mut(self, i); } } fn visit_path_segment_mut(&mut self, seg: &mut PathSegment) { if seg.ident == "Self" { let span = seg.span(); let this = &self.0; *seg = parse_quote_spanned!(span=> #this); } else { syn::visit_mut::visit_path_segment_mut(self, seg); } } fn visit_item_mut(&mut self, _: &mut Item) { // Do not descend into items, since items reset/change what `Self` refers to. }}
// SPDX-License-Identifier: Apache-2.0 OR MIT
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{
parse::{End, Nothing, Parse},
parse_quote, parse_quote_spanned,
spanned::Spanned,
visit_mut::VisitMut,
Attribute, Field, Generics, Ident, Item, PathSegment, Type, TypePath, Visibility, WhereClause,
};
use crate::diagnostics::{DiagCtxt, ErrorGuaranteed};
pub(crate) mod kw {
syn::custom_keyword!(PinnedDrop);
}
pub(crate) enum Args {
Nothing(Nothing),
#[allow(dead_code)]
PinnedDrop(kw::PinnedDrop),
}
impl Parse for Args {
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
let lh = input.lookahead1();
if lh.peek(End) {
input.parse().map(Self::Nothing)
} else if lh.peek(kw::PinnedDrop) {
input.parse().map(Self::PinnedDrop)
} else {
Err(lh.error())
}
}
}
struct FieldInfo<'a> {
field: &'a Field,
pinned: bool,
cfg_attrs: Vec<&'a Attribute>,
}
pub(crate) fn pin_data(
args: Args,
input: Item,
dcx: &mut DiagCtxt,
) -> Result<TokenStream, ErrorGuaranteed> {
let mut struct_ = match input {
Item::Struct(struct_) => struct_,
Item::Enum(enum_) => {
return Err(dcx.error(
enum_.enum_token,
"`#[pin_data]` only supports structs for now",
));
}
Item::Union(union) => {
return Err(dcx.error(
union.union_token,
"`#[pin_data]` only supports structs for now",
));
}
rest => {
return Err(dcx.error(
rest,
"`#[pin_data]` can only be applied to struct, enum and union definitions",
));
}
};
// The generics might contain the `Self` type. Since this macro will define a new type with the
// same generics and bounds, this poses a problem: `Self` will refer to the new type as opposed
// to this struct definition. Therefore we have to replace `Self` with the concrete name.
let mut replacer = {
let name = &struct_.ident;
let (_, ty_generics, _) = struct_.generics.split_for_impl();
SelfReplacer(parse_quote!(#name #ty_generics))
};
replacer.visit_generics_mut(&mut struct_.generics);
replacer.visit_fields_mut(&mut struct_.fields);
let fields: Vec<FieldInfo<'_>> = struct_
.fields
.iter_mut()
.map(|field| {
let len = field.attrs.len();
field.attrs.retain(|a| !a.path().is_ident("pin"));
let pinned = len != field.attrs.len();
let cfg_attrs = field
.attrs
.iter()
.filter(|a| a.path().is_ident("cfg"))
.collect();
FieldInfo {
field: &*field,
pinned,
cfg_attrs,
}
})
.collect();
for field in &fields {
let ident = field.field.ident.as_ref().unwrap();
if !field.pinned && is_phantom_pinned(&field.field.ty) {
dcx.warn(
field.field,
format!(
"The field `{ident}` of type `PhantomPinned` only has an effect \
if it has the `#[pin]` attribute",
),
);
}
}
let unpin_impl = generate_unpin_impl(&struct_.ident, &struct_.generics, &fields);
let drop_impl = generate_drop_impl(&struct_.ident, &struct_.generics, args);
let projections =
generate_projections(&struct_.vis, &struct_.ident, &struct_.generics, &fields);
let the_pin_data =
generate_the_pin_data(&struct_.vis, &struct_.ident, &struct_.generics, &fields);
Ok(quote! {
#struct_
#projections
// We put the rest into this const item, because it then will not be accessible to anything
// outside.
const _: () = {
#the_pin_data
#unpin_impl
#drop_impl
};
})
}
fn is_phantom_pinned(ty: &Type) -> bool {
match ty {
Type::Path(TypePath { qself: None, path }) => {
// Cannot possibly refer to `PhantomPinned` (except alias, but that's on the user).
if path.segments.len() > 3 {
return false;
}
// If there is a `::`, then the path needs to be `::core::marker::PhantomPinned` or
// `::std::marker::PhantomPinned`.
if path.leading_colon.is_some() && path.segments.len() != 3 {
return false;
}
let expected: Vec<&[&str]> = vec![&["PhantomPinned"], &["marker"], &["core", "std"]];
for (actual, expected) in path.segments.iter().rev().zip(expected) {
if !actual.arguments.is_empty() || expected.iter().all(|e| actual.ident != e) {
return false;
}
}
true
}
_ => false,
}
}
fn generate_unpin_impl(
ident: &Ident,
generics: &Generics,
fields: &[FieldInfo<'_>],
) -> TokenStream {
let (_, ty_generics, _) = generics.split_for_impl();
let mut generics_with_pin_lt = generics.clone();
generics_with_pin_lt.params.insert(0, parse_quote!('__pin));
generics_with_pin_lt.make_where_clause();
let (
impl_generics_with_pin_lt,
ty_generics_with_pin_lt,
Some(WhereClause {
where_token,
predicates,
}),
) = generics_with_pin_lt.split_for_impl()
else {
unreachable!()
};
let pinned_fields = fields.iter().filter(|f| f.pinned).map(|f| {
let ident = f.field.ident.as_ref().unwrap();
let ty = &f.field.ty;
let cfg_attrs = &f.cfg_attrs;
quote!(
#(#cfg_attrs)*
#ident: #ty
)
});
quote! {
// This struct will be used for the unpin analysis. It is needed, because only structurally
// pinned fields are relevant whether the struct should implement `Unpin`.
#[allow(
dead_code, // The fields below are never used.
non_snake_case // The warning will be emitted on the struct definition.
)]
struct __Unpin #generics_with_pin_lt
#where_token
#predicates
{
__phantom_pin: ::pin_init::__internal::PhantomInvariantLifetime<'__pin>,
__phantom: ::pin_init::__internal::PhantomInvariant<#ident #ty_generics>,
#(#pinned_fields),*
}
#[doc(hidden)]
impl #impl_generics_with_pin_lt ::core::marker::Unpin for #ident #ty_generics
#where_token
__Unpin #ty_generics_with_pin_lt: ::core::marker::Unpin,
#predicates
{}
}
}
fn generate_drop_impl(ident: &Ident, generics: &Generics, args: Args) -> TokenStream {
let (impl_generics, ty_generics, whr) = generics.split_for_impl();
let has_pinned_drop = matches!(args, Args::PinnedDrop(_));
// We need to disallow normal `Drop` implementation, the exact behavior depends on whether
// `PinnedDrop` was specified in `args`.
if has_pinned_drop {
// When `PinnedDrop` was specified we just implement `Drop` and delegate.
quote! {
impl #impl_generics ::core::ops::Drop for #ident #ty_generics
#whr
{
fn drop(&mut self) {
// SAFETY: Since this is a destructor, `self` will not move after this function
// terminates, since it is inaccessible.
let pinned = unsafe { ::core::pin::Pin::new_unchecked(self) };
// SAFETY: Since this is a drop function, we can create this token to call the
// pinned destructor of this type.
let token = unsafe { ::pin_init::__internal::OnlyCallFromDrop::new() };
::pin_init::PinnedDrop::drop(pinned, token);
}
}
}
} else {
// When no `PinnedDrop` was specified, then we have to prevent implementing drop.
quote! {
// We prevent this by creating a trait that will be implemented for all types implementing
// `Drop`. Additionally we will implement this trait for the struct leading to a conflict,
// if it also implements `Drop`
trait MustNotImplDrop {}
#[expect(drop_bounds)]
impl<T: ::core::ops::Drop + ?::core::marker::Sized> MustNotImplDrop for T {}
impl #impl_generics MustNotImplDrop for #ident #ty_generics
#whr
{}
// We also take care to prevent users from writing a useless `PinnedDrop` implementation.
// They might implement `PinnedDrop` correctly for the struct, but forget to give
// `PinnedDrop` as the parameter to `#[pin_data]`.
#[expect(non_camel_case_types)]
trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {}
impl<T: ::pin_init::PinnedDrop + ?::core::marker::Sized>
UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {}
impl #impl_generics
UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for #ident #ty_generics
#whr
{}
}
}
}
fn generate_projections(
vis: &Visibility,
ident: &Ident,
generics: &Generics,
fields: &[FieldInfo<'_>],
) -> TokenStream {
let (impl_generics, ty_generics, _) = generics.split_for_impl();
let mut generics_with_pin_lt = generics.clone();
generics_with_pin_lt.params.insert(0, parse_quote!('__pin));
let (_, ty_generics_with_pin_lt, whr) = generics_with_pin_lt.split_for_impl();
let projection = format_ident!("{ident}Projection");
let this = format_ident!("this");
let (fields_decl, fields_proj): (Vec<_>, Vec<_>) = fields
.iter()
.map(|field| {
let Field { vis, ident, ty, .. } = &field.field;
let cfg_attrs = &field.cfg_attrs;
let ident = ident
.as_ref()
.expect("only structs with named fields are supported");
if field.pinned {
(
quote!(
#(#cfg_attrs)*
#vis #ident: ::core::pin::Pin<&'__pin mut #ty>,
),
quote!(
#(#cfg_attrs)*
// SAFETY: this field is structurally pinned.
#ident: unsafe { ::core::pin::Pin::new_unchecked(&mut #this.#ident) },
),
)
} else {
(
quote!(
#(#cfg_attrs)*
#vis #ident: &'__pin mut #ty,
),
quote!(
#(#cfg_attrs)*
#ident: &mut #this.#ident,
),
)
}
})
.collect();
let structurally_pinned_fields_docs = fields
.iter()
.filter(|f| f.pinned)
.map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap()));
let not_structurally_pinned_fields_docs = fields
.iter()
.filter(|f| !f.pinned)
.map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap()));
let docs = format!(" Pin-projections of [`{ident}`]");
quote! {
#[doc = #docs]
// Allow `non_snake_case` since the same warning will be emitted on
// the struct definition.
#[allow(dead_code, non_snake_case)]
#[doc(hidden)]
#vis struct #projection #generics_with_pin_lt
#whr
{
#(#fields_decl)*
___pin_phantom_data: ::core::marker::PhantomData<&'__pin mut ()>,
}
impl #impl_generics #ident #ty_generics
#whr
{
/// Pin-projects all fields of `Self`.
///
/// These fields are structurally pinned:
#(#[doc = #structurally_pinned_fields_docs])*
///
/// These fields are **not** structurally pinned:
#(#[doc = #not_structurally_pinned_fields_docs])*
#[inline]
#vis fn project<'__pin>(
self: ::core::pin::Pin<&'__pin mut Self>,
) -> #projection #ty_generics_with_pin_lt {
// SAFETY: we only give access to `&mut` for fields not structurally pinned.
let #this = unsafe { ::core::pin::Pin::get_unchecked_mut(self) };
#projection {
#(#fields_proj)*
___pin_phantom_data: ::core::marker::PhantomData,
}
}
}
}
}
fn generate_the_pin_data(
vis: &Visibility,
struct_name: &Ident,
generics: &Generics,
fields: &[FieldInfo<'_>],
) -> TokenStream {
let (impl_generics, ty_generics, whr) = generics.split_for_impl();
// For every field, we create an initializing projection function according to its projection
// type. If a field is structurally pinned, we create a `Slot` with `Pinned` which must be
// initialized via `PinInit`; if it is not structurally pinned, then we create a `Slot` with
// `Unpinned` which allows initialization via `Init`.
let field_accessors = fields
.iter()
.map(|f| {
let Field { vis, ident, ty, .. } = f.field;
let cfg_attrs = &f.cfg_attrs;
let field_name = ident
.as_ref()
.expect("only structs with named fields are supported");
let pin_marker = if f.pinned {
quote!(Pinned)
} else {
quote!(Unpinned)
};
quote! {
/// # Safety
///
/// - `slot` is valid and properly aligned.
/// - `(*slot).#field_name` is properly aligned.
/// - `(*slot).#field_name` points to uninitialized and exclusively accessed
/// memory.
#(#cfg_attrs)*
// Allow `non_snake_case` since the same warning will be emitted on
// the struct definition.
#[allow(non_snake_case)]
#[inline(always)]
#vis unsafe fn #field_name(
self,
slot: *mut #struct_name #ty_generics,
) -> ::pin_init::__internal::Slot<::pin_init::__internal::#pin_marker, #ty> {
// SAFETY:
// - If `#pin_marker` is `Pinned`, the corresponding field is structurally
// pinned.
// - Other safety requirements follows the safety requirement.
unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).#field_name) }
}
}
})
.collect::<TokenStream>();
quote! {
// We declare this struct which will host all of the projection function for our type. It
// will be invariant over all generic parameters which are inherited from the struct.
#[doc(hidden)]
#vis struct __ThePinData #generics
#whr
{
__phantom: ::pin_init::__internal::PhantomInvariant<#struct_name #ty_generics>,
}
impl #impl_generics ::core::clone::Clone for __ThePinData #ty_generics
#whr
{
fn clone(&self) -> Self { *self }
}
impl #impl_generics ::core::marker::Copy for __ThePinData #ty_generics
#whr
{}
#[allow(dead_code)] // Some functions might never be used and private.
#[expect(clippy::missing_safety_doc)]
impl #impl_generics __ThePinData #ty_generics
#whr
{
/// Type inference helper function.
#[inline(always)]
#vis fn __make_closure<__F, __E>(self, f: __F) -> __F
where
__F: FnOnce(*mut #struct_name #ty_generics) ->
::core::result::Result<::pin_init::__internal::InitOk, __E>,
{
f
}
#field_accessors
}
// SAFETY: We have added the correct projection functions above to `__ThePinData` and
// we also use the least restrictive generics possible.
unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #struct_name #ty_generics
#whr
{
type PinData = __ThePinData #ty_generics;
unsafe fn __pin_data() -> Self::PinData {
__ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() }
}
}
}
}
struct SelfReplacer(PathSegment);
impl VisitMut for SelfReplacer {
fn visit_path_mut(&mut self, i: &mut syn::Path) {
if i.is_ident("Self") {
let span = i.span();
let seg = &self.0;
*i = parse_quote_spanned!(span=> #seg);
} else {
syn::visit_mut::visit_path_mut(self, i);
}
}
fn visit_path_segment_mut(&mut self, seg: &mut PathSegment) {
if seg.ident == "Self" {
let span = seg.span();
let this = &self.0;
*seg = parse_quote_spanned!(span=> #this);
} else {
syn::visit_mut::visit_path_segment_mut(self, seg);
}
}
fn visit_item_mut(&mut self, _: &mut Item) {
// Do not descend into items, since items reset/change what `Self` refers to.
}
}