Support fieldless `recursively_pinned` structs and enums. (In the case of structs, that's empty structs -- in the case of enums, it's C-like enums.) PiperOrigin-RevId: 447449578
diff --git a/rs_bindings_from_cc/support/ctor_proc_macros.rs b/rs_bindings_from_cc/support/ctor_proc_macros.rs index 36b44d4..5a7bd0f 100644 --- a/rs_bindings_from_cc/support/ctor_proc_macros.rs +++ b/rs_bindings_from_cc/support/ctor_proc_macros.rs
@@ -98,16 +98,29 @@ projected.ident = projected_ident(&projected.ident); let projected_ident = &projected.ident; - let lifetime = syn::Lifetime::new("'proj", Span::call_site()); assert_eq!( projected.generics.params.len(), 0, "pin projection is currently not implemented for generic structs" ); - projected - .generics - .params - .push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(lifetime.clone()))); + + let is_fieldless = match &projected.data { + syn::Data::Struct(data) => data.fields.is_empty(), + syn::Data::Enum(e) => e.variants.iter().all(|variant| variant.fields.is_empty()), + syn::Data::Union(_) => unimplemented!(), + }; + + let lifetime; + if is_fieldless { + lifetime = quote! {}; + } else { + let syn_lifetime = syn::Lifetime::new("'proj", Span::call_site()); + projected + .generics + .params + .push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(syn_lifetime.clone()))); + lifetime = quote! {#syn_lifetime}; + } let project_field = |field: &mut syn::Field| { field.attrs.clear(); @@ -219,7 +232,9 @@ #projected_impl impl #name { - fn project(self: ::std::pin::Pin<&mut Self>) -> #projected_ident<'_> { + #[must_use] + #[inline(always)] + fn project(self: ::std::pin::Pin<&mut Self>) -> #projected_ident { #projected_ident::new(self) } }
diff --git a/rs_bindings_from_cc/support/ctor_proc_macros_test.rs b/rs_bindings_from_cc/support/ctor_proc_macros_test.rs index 48c9e20..a469658 100644 --- a/rs_bindings_from_cc/support/ctor_proc_macros_test.rs +++ b/rs_bindings_from_cc/support/ctor_proc_macros_test.rs
@@ -48,6 +48,40 @@ } #[test] +fn test_recursively_pinned_unit_struct() { + #[::ctor::recursively_pinned] + struct S; + let _ = Box::pin(S).as_mut().project(); + assert_eq!(::std::mem::size_of::<::ctor::projected!(S)>(), 0); +} + +#[test] +fn test_recursively_pinned_fieldless_struct() { + #[::ctor::recursively_pinned] + struct S {} + let _ = Box::pin(S {}).as_mut().project(); + assert_eq!(::std::mem::size_of::<::ctor::projected!(S)>(), 0); +} + +#[test] +fn test_recursively_pinned_fieldless_tuple_struct() { + #[::ctor::recursively_pinned] + struct S(); + let _ = Box::pin(S()).as_mut().project(); + assert_eq!(::std::mem::size_of::<::ctor::projected!(S)>(), 0); +} + +#[test] +fn test_recursively_pinned_fieldless_enum() { + #[::ctor::recursively_pinned] + enum E { + A, + } + let <::ctor::projected!(E)>::A = Box::pin(E::A).as_mut().project(); + assert_eq!(::std::mem::size_of::<::ctor::projected!(E)>(), 0); +} + +#[test] fn test_recursively_pinned_struct() { #[::ctor::recursively_pinned] struct S {