| // SPDX-License-Identifier: Apache-2.0 OR MIT | |
| use proc_macro2::TokenStream; | |
| use quote::quote; | |
| use syn::{parse_quote, Data, DeriveInput, Field, Fields}; | |
| use crate::{diagnostics::ErrorGuaranteed, DiagCtxt}; | |
| pub(crate) fn derive( | |
| input: DeriveInput, | |
| dcx: &mut DiagCtxt, | |
| ) -> Result<TokenStream, ErrorGuaranteed> { | |
| let fields = match input.data { | |
| Data::Struct(data_struct) => data_struct.fields, | |
| Data::Union(data_union) => Fields::Named(data_union.fields), | |
| Data::Enum(data_enum) => { | |
| return Err(dcx.error(data_enum.enum_token, "cannot derive `Zeroable` for an enum")); | |
| } | |
| }; | |
| let name = input.ident; | |
| let mut generics = input.generics; | |
| for param in generics.type_params_mut() { | |
| param.bounds.insert(0, parse_quote!(::pin_init::Zeroable)); | |
| } | |
| let (impl_gen, ty_gen, whr) = generics.split_for_impl(); | |
| let field_type = fields.iter().map(|field| &field.ty); | |
| Ok(quote! { | |
| // SAFETY: Every field type implements `Zeroable` and padding bytes may be zero. | |
| #[automatically_derived] | |
| unsafe impl #impl_gen ::pin_init::Zeroable for #name #ty_gen | |
| #whr | |
| {} | |
| const _: () = { | |
| fn assert_zeroable<T: ?::core::marker::Sized + ::pin_init::Zeroable>() {} | |
| fn ensure_zeroable #impl_gen () | |
| #whr | |
| { | |
| #( | |
| assert_zeroable::<#field_type>(); | |
| )* | |
| } | |
| }; | |
| }) | |
| } | |
| pub(crate) fn maybe_derive( | |
| input: DeriveInput, | |
| dcx: &mut DiagCtxt, | |
| ) -> Result<TokenStream, ErrorGuaranteed> { | |
| let fields = match input.data { | |
| Data::Struct(data_struct) => data_struct.fields, | |
| Data::Union(data_union) => Fields::Named(data_union.fields), | |
| Data::Enum(data_enum) => { | |
| return Err(dcx.error(data_enum.enum_token, "cannot derive `Zeroable` for an enum")); | |
| } | |
| }; | |
| let name = input.ident; | |
| let mut generics = input.generics; | |
| for param in generics.type_params_mut() { | |
| param.bounds.insert(0, parse_quote!(::pin_init::Zeroable)); | |
| } | |
| for Field { ty, .. } in fields { | |
| generics | |
| .make_where_clause() | |
| .predicates | |
| // the `for<'__dummy>` HRTB makes this not error without the `trivial_bounds` | |
| // feature <https://github.com/rust-lang/rust/issues/48214#issuecomment-2557829956>. | |
| .push(parse_quote!(#ty: for<'__dummy> ::pin_init::Zeroable)); | |
| } | |
| let (impl_gen, ty_gen, whr) = generics.split_for_impl(); | |
| Ok(quote! { | |
| // SAFETY: Every field type implements `Zeroable` and padding bytes may be zero. | |
| #[automatically_derived] | |
| unsafe impl #impl_gen ::pin_init::Zeroable for #name #ty_gen | |
| #whr | |
| {} | |
| }) | |
| } |