1#![allow(unknown_lints)]
18#![deny(renamed_and_removed_lints)]
19#![deny(clippy::all, clippy::missing_safety_doc, clippy::undocumented_unsafe_blocks)]
20#![deny(
21 rustdoc::bare_urls,
22 rustdoc::broken_intra_doc_links,
23 rustdoc::invalid_codeblock_attributes,
24 rustdoc::invalid_html_tags,
25 rustdoc::invalid_rust_codeblocks,
26 rustdoc::missing_crate_level_docs,
27 rustdoc::private_intra_doc_links
28)]
29#![recursion_limit = "128"]
30
31mod r#enum;
32mod ext;
33#[cfg(test)]
34mod output_tests;
35mod repr;
36
37use proc_macro2::{TokenStream, TokenTree};
38use quote::ToTokens;
39
40use {
41 proc_macro2::Span,
42 quote::quote,
43 syn::{
44 parse_quote, Attribute, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error, Expr,
45 ExprLit, ExprUnary, GenericParam, Ident, Lit, Meta, Path, Type, UnOp, WherePredicate,
46 },
47};
48
49use {crate::ext::*, crate::repr::*};
50
51macro_rules! derive {
75 ($trait:ident => $outer:ident => $inner:ident) => {
76 #[proc_macro_derive($trait, attributes(zerocopy))]
77 pub fn $outer(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
78 let ast = syn::parse_macro_input!(ts as DeriveInput);
79 let zerocopy_crate = match extract_zerocopy_crate(&ast.attrs) {
80 Ok(zerocopy_crate) => zerocopy_crate,
81 Err(e) => return e.into_compile_error().into(),
82 };
83 $inner(&ast, Trait::$trait, &zerocopy_crate).into_ts().into()
84 }
85 };
86}
87
88trait IntoTokenStream {
89 fn into_ts(self) -> TokenStream;
90}
91
92impl IntoTokenStream for TokenStream {
93 fn into_ts(self) -> TokenStream {
94 self
95 }
96}
97
98impl IntoTokenStream for Result<TokenStream, Error> {
99 fn into_ts(self) -> TokenStream {
100 match self {
101 Ok(ts) => ts,
102 Err(err) => err.to_compile_error(),
103 }
104 }
105}
106
107fn extract_zerocopy_crate(attrs: &[Attribute]) -> Result<Path, Error> {
110 let mut path = parse_quote!(::zerocopy);
111
112 for attr in attrs {
113 if let Meta::List(ref meta_list) = attr.meta {
114 if meta_list.path.is_ident("zerocopy") {
115 attr.parse_nested_meta(|meta| {
116 if meta.path.is_ident("crate") {
117 let expr = meta.value().and_then(|value| value.parse());
118 if let Ok(Expr::Lit(ExprLit { lit: Lit::Str(lit), .. })) = expr {
119 if let Ok(path_lit) = lit.parse() {
120 path = path_lit;
121 return Ok(());
122 }
123 }
124
125 return Err(Error::new(
126 Span::call_site(),
127 "`crate` attribute requires a path as the value",
128 ));
129 }
130
131 Err(Error::new(
132 Span::call_site(),
133 format!("unknown attribute encountered: {}", meta.path.into_token_stream()),
134 ))
135 })?;
136 }
137 }
138 }
139
140 Ok(path)
141}
142
143derive!(KnownLayout => derive_known_layout => derive_known_layout_inner);
144derive!(Immutable => derive_no_cell => derive_no_cell_inner);
145derive!(TryFromBytes => derive_try_from_bytes => derive_try_from_bytes_inner);
146derive!(FromZeros => derive_from_zeros => derive_from_zeros_inner);
147derive!(FromBytes => derive_from_bytes => derive_from_bytes_inner);
148derive!(IntoBytes => derive_into_bytes => derive_into_bytes_inner);
149derive!(Unaligned => derive_unaligned => derive_unaligned_inner);
150derive!(ByteHash => derive_hash => derive_hash_inner);
151derive!(ByteEq => derive_eq => derive_eq_inner);
152derive!(SplitAt => derive_split_at => derive_split_at_inner);
153
154#[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")]
156#[doc(hidden)]
157#[proc_macro_derive(FromZeroes)]
158pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
159 derive_from_zeros(ts)
160}
161
162#[deprecated(since = "0.8.0", note = "`AsBytes` was renamed to `IntoBytes`")]
164#[doc(hidden)]
165#[proc_macro_derive(AsBytes)]
166pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
167 derive_into_bytes(ts)
168}
169
170fn derive_known_layout_inner(
171 ast: &DeriveInput,
172 _top_level: Trait,
173 zerocopy_crate: &Path,
174) -> Result<TokenStream, Error> {
175 let is_repr_c_struct = match &ast.data {
176 Data::Struct(..) => {
177 let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
178 if repr.is_c() {
179 Some(repr)
180 } else {
181 None
182 }
183 }
184 Data::Enum(..) | Data::Union(..) => None,
185 };
186
187 let fields = ast.data.fields();
188
189 let (self_bounds, inner_extras, outer_extras) = if let (
190 Some(repr),
191 Some((trailing_field, leading_fields)),
192 ) = (is_repr_c_struct, fields.split_last())
193 {
194 let (_vis, trailing_field_name, trailing_field_ty) = trailing_field;
195 let leading_fields_tys = leading_fields.iter().map(|(_vis, _name, ty)| ty);
196
197 let core_path = quote!(#zerocopy_crate::util::macro_util::core_reexport);
198 let repr_align = repr
199 .get_align()
200 .map(|align| {
201 let align = align.t.get();
202 quote!(#core_path::num::NonZeroUsize::new(#align as usize))
203 })
204 .unwrap_or_else(|| quote!(#core_path::option::Option::None));
205 let repr_packed = repr
206 .get_packed()
207 .map(|packed| {
208 let packed = packed.get();
209 quote!(#core_path::num::NonZeroUsize::new(#packed as usize))
210 })
211 .unwrap_or_else(|| quote!(#core_path::option::Option::None));
212
213 let make_methods = |trailing_field_ty| {
214 quote! {
215 #[inline(always)]
245 fn raw_from_ptr_len(
246 bytes: #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull<u8>,
247 meta: Self::PointerMetadata,
248 ) -> #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull<Self> {
249 use #zerocopy_crate::KnownLayout;
250 let trailing = <#trailing_field_ty as KnownLayout>::raw_from_ptr_len(bytes, meta);
251 let slf = trailing.as_ptr() as *mut Self;
252 unsafe { #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull::new_unchecked(slf) }
254 }
255
256 #[inline(always)]
257 fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata {
258 <#trailing_field_ty>::pointer_to_metadata(ptr as *mut _)
259 }
260 }
261 };
262
263 let inner_extras = {
264 let leading_fields_tys = leading_fields_tys.clone();
265 let methods = make_methods(*trailing_field_ty);
266 let (_, ty_generics, _) = ast.generics.split_for_impl();
267
268 quote!(
269 type PointerMetadata = <#trailing_field_ty as #zerocopy_crate::KnownLayout>::PointerMetadata;
270
271 type MaybeUninit = __ZerocopyKnownLayoutMaybeUninit #ty_generics;
272
273 const LAYOUT: #zerocopy_crate::DstLayout = {
288 use #zerocopy_crate::util::macro_util::core_reexport::num::NonZeroUsize;
289 use #zerocopy_crate::{DstLayout, KnownLayout};
290
291 let repr_align = #repr_align;
292 let repr_packed = #repr_packed;
293
294 DstLayout::new_zst(repr_align)
295 #(.extend(DstLayout::for_type::<#leading_fields_tys>(), repr_packed))*
296 .extend(<#trailing_field_ty as KnownLayout>::LAYOUT, repr_packed)
297 .pad_to_align()
298 };
299
300 #methods
301 )
302 };
303
304 let outer_extras = {
305 let ident = &ast.ident;
306 let vis = &ast.vis;
307 let params = &ast.generics.params;
308 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
309
310 let predicates = if let Some(where_clause) = where_clause {
311 where_clause.predicates.clone()
312 } else {
313 Default::default()
314 };
315
316 let field_index =
319 |name| Ident::new(&format!("__Zerocopy_Field_{}", name), ident.span());
320
321 let field_indices: Vec<_> =
322 fields.iter().map(|(_vis, name, _ty)| field_index(name)).collect();
323
324 let field_defs = field_indices.iter().zip(&fields).map(|(idx, (vis, _, _))| {
326 quote! {
327 #[allow(non_camel_case_types)]
328 #vis struct #idx;
329 }
330 });
331
332 let field_impls = field_indices.iter().zip(&fields).map(|(idx, (_, _, ty))| quote! {
333 unsafe impl #impl_generics #zerocopy_crate::util::macro_util::Field<#idx> for #ident #ty_generics
335 where
336 #predicates
337 {
338 type Type = #ty;
339 }
340 });
341
342 let trailing_field_index = field_index(trailing_field_name);
343 let leading_field_indices =
344 leading_fields.iter().map(|(_vis, name, _ty)| field_index(name));
345
346 let trailing_field_ty = quote! {
347 <#ident #ty_generics as
348 #zerocopy_crate::util::macro_util::Field<#trailing_field_index>
349 >::Type
350 };
351
352 let methods = make_methods(&parse_quote! {
353 <#trailing_field_ty as #zerocopy_crate::KnownLayout>::MaybeUninit
354 });
355
356 quote! {
357 #(#field_defs)*
358
359 #(#field_impls)*
360
361 #repr
369 #[doc(hidden)]
370 #[allow(private_bounds)]
374 #vis struct __ZerocopyKnownLayoutMaybeUninit<#params> (
375 #(#zerocopy_crate::util::macro_util::core_reexport::mem::MaybeUninit<
376 <#ident #ty_generics as
377 #zerocopy_crate::util::macro_util::Field<#leading_field_indices>
378 >::Type
379 >,)*
380 #zerocopy_crate::util::macro_util::core_reexport::mem::ManuallyDrop<
387 <#trailing_field_ty as #zerocopy_crate::KnownLayout>::MaybeUninit
388 >
389 )
390 where
391 #trailing_field_ty: #zerocopy_crate::KnownLayout,
392 #predicates;
393
394 unsafe impl #impl_generics #zerocopy_crate::KnownLayout for __ZerocopyKnownLayoutMaybeUninit #ty_generics
401 where
402 #trailing_field_ty: #zerocopy_crate::KnownLayout,
403 #predicates
404 {
405 #[allow(clippy::missing_inline_in_public_items)]
406 fn only_derive_is_allowed_to_implement_this_trait() {}
407
408 type PointerMetadata = <#ident #ty_generics as #zerocopy_crate::KnownLayout>::PointerMetadata;
409
410 type MaybeUninit = Self;
411
412 const LAYOUT: #zerocopy_crate::DstLayout = <#ident #ty_generics as #zerocopy_crate::KnownLayout>::LAYOUT;
413
414 #methods
415 }
416 }
417 };
418
419 (SelfBounds::None, inner_extras, Some(outer_extras))
420 } else {
421 (
425 SelfBounds::SIZED,
426 quote!(
427 type PointerMetadata = ();
428 type MaybeUninit =
429 #zerocopy_crate::util::macro_util::core_reexport::mem::MaybeUninit<Self>;
430
431 const LAYOUT: #zerocopy_crate::DstLayout = #zerocopy_crate::DstLayout::for_type::<Self>();
435
436 #[inline(always)]
441 fn raw_from_ptr_len(
442 bytes: #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull<u8>,
443 _meta: (),
444 ) -> #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull<Self>
445 {
446 bytes.cast::<Self>()
447 }
448
449 #[inline(always)]
450 fn pointer_to_metadata(_ptr: *mut Self) -> () {}
451 ),
452 None,
453 )
454 };
455
456 Ok(match &ast.data {
457 Data::Struct(strct) => {
458 let require_trait_bound_on_field_types = if self_bounds == SelfBounds::SIZED {
459 FieldBounds::None
460 } else {
461 FieldBounds::TRAILING_SELF
462 };
463
464 ImplBlockBuilder::new(
469 ast,
470 strct,
471 Trait::KnownLayout,
472 require_trait_bound_on_field_types,
473 zerocopy_crate,
474 )
475 .self_type_trait_bounds(self_bounds)
476 .inner_extras(inner_extras)
477 .outer_extras(outer_extras)
478 .build()
479 }
480 Data::Enum(enm) => {
481 ImplBlockBuilder::new(ast, enm, Trait::KnownLayout, FieldBounds::None, zerocopy_crate)
484 .self_type_trait_bounds(SelfBounds::SIZED)
485 .inner_extras(inner_extras)
486 .outer_extras(outer_extras)
487 .build()
488 }
489 Data::Union(unn) => {
490 ImplBlockBuilder::new(ast, unn, Trait::KnownLayout, FieldBounds::None, zerocopy_crate)
493 .self_type_trait_bounds(SelfBounds::SIZED)
494 .inner_extras(inner_extras)
495 .outer_extras(outer_extras)
496 .build()
497 }
498 })
499}
500
501fn derive_no_cell_inner(
502 ast: &DeriveInput,
503 _top_level: Trait,
504 zerocopy_crate: &Path,
505) -> TokenStream {
506 match &ast.data {
507 Data::Struct(strct) => ImplBlockBuilder::new(
508 ast,
509 strct,
510 Trait::Immutable,
511 FieldBounds::ALL_SELF,
512 zerocopy_crate,
513 )
514 .build(),
515 Data::Enum(enm) => {
516 ImplBlockBuilder::new(ast, enm, Trait::Immutable, FieldBounds::ALL_SELF, zerocopy_crate)
517 .build()
518 }
519 Data::Union(unn) => {
520 ImplBlockBuilder::new(ast, unn, Trait::Immutable, FieldBounds::ALL_SELF, zerocopy_crate)
521 .build()
522 }
523 }
524}
525
526fn derive_try_from_bytes_inner(
527 ast: &DeriveInput,
528 top_level: Trait,
529 zerocopy_crate: &Path,
530) -> Result<TokenStream, Error> {
531 match &ast.data {
532 Data::Struct(strct) => derive_try_from_bytes_struct(ast, strct, top_level, zerocopy_crate),
533 Data::Enum(enm) => derive_try_from_bytes_enum(ast, enm, top_level, zerocopy_crate),
534 Data::Union(unn) => Ok(derive_try_from_bytes_union(ast, unn, top_level, zerocopy_crate)),
535 }
536}
537
538fn derive_from_zeros_inner(
539 ast: &DeriveInput,
540 top_level: Trait,
541 zerocopy_crate: &Path,
542) -> Result<TokenStream, Error> {
543 let try_from_bytes = derive_try_from_bytes_inner(ast, top_level, zerocopy_crate)?;
544 let from_zeros = match &ast.data {
545 Data::Struct(strct) => derive_from_zeros_struct(ast, strct, zerocopy_crate),
546 Data::Enum(enm) => derive_from_zeros_enum(ast, enm, zerocopy_crate)?,
547 Data::Union(unn) => derive_from_zeros_union(ast, unn, zerocopy_crate),
548 };
549 Ok(IntoIterator::into_iter([try_from_bytes, from_zeros]).collect())
550}
551
552fn derive_from_bytes_inner(
553 ast: &DeriveInput,
554 top_level: Trait,
555 zerocopy_crate: &Path,
556) -> Result<TokenStream, Error> {
557 let from_zeros = derive_from_zeros_inner(ast, top_level, zerocopy_crate)?;
558 let from_bytes = match &ast.data {
559 Data::Struct(strct) => derive_from_bytes_struct(ast, strct, zerocopy_crate),
560 Data::Enum(enm) => derive_from_bytes_enum(ast, enm, zerocopy_crate)?,
561 Data::Union(unn) => derive_from_bytes_union(ast, unn, zerocopy_crate),
562 };
563
564 Ok(IntoIterator::into_iter([from_zeros, from_bytes]).collect())
565}
566
567fn derive_into_bytes_inner(
568 ast: &DeriveInput,
569 _top_level: Trait,
570 zerocopy_crate: &Path,
571) -> Result<TokenStream, Error> {
572 match &ast.data {
573 Data::Struct(strct) => derive_into_bytes_struct(ast, strct, zerocopy_crate),
574 Data::Enum(enm) => derive_into_bytes_enum(ast, enm, zerocopy_crate),
575 Data::Union(unn) => derive_into_bytes_union(ast, unn, zerocopy_crate),
576 }
577}
578
579fn derive_unaligned_inner(
580 ast: &DeriveInput,
581 _top_level: Trait,
582 zerocopy_crate: &Path,
583) -> Result<TokenStream, Error> {
584 match &ast.data {
585 Data::Struct(strct) => derive_unaligned_struct(ast, strct, zerocopy_crate),
586 Data::Enum(enm) => derive_unaligned_enum(ast, enm, zerocopy_crate),
587 Data::Union(unn) => derive_unaligned_union(ast, unn, zerocopy_crate),
588 }
589}
590
591fn derive_hash_inner(
592 ast: &DeriveInput,
593 _top_level: Trait,
594 zerocopy_crate: &Path,
595) -> Result<TokenStream, Error> {
596 let type_ident = &ast.ident;
602 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
603 let where_predicates = where_clause.map(|clause| &clause.predicates);
604 Ok(quote! {
605 #[allow(deprecated)]
608 #[automatically_derived]
611 impl #impl_generics #zerocopy_crate::util::macro_util::core_reexport::hash::Hash for #type_ident #ty_generics
612 where
613 Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
614 #where_predicates
615 {
616 fn hash<H>(&self, state: &mut H)
617 where
618 H: #zerocopy_crate::util::macro_util::core_reexport::hash::Hasher,
619 {
620 #zerocopy_crate::util::macro_util::core_reexport::hash::Hasher::write(
621 state,
622 #zerocopy_crate::IntoBytes::as_bytes(self)
623 )
624 }
625
626 fn hash_slice<H>(data: &[Self], state: &mut H)
627 where
628 H: #zerocopy_crate::util::macro_util::core_reexport::hash::Hasher,
629 {
630 #zerocopy_crate::util::macro_util::core_reexport::hash::Hasher::write(
631 state,
632 #zerocopy_crate::IntoBytes::as_bytes(data)
633 )
634 }
635 }
636 })
637}
638
639fn derive_eq_inner(
640 ast: &DeriveInput,
641 _top_level: Trait,
642 zerocopy_crate: &Path,
643) -> Result<TokenStream, Error> {
644 let type_ident = &ast.ident;
650 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
651 let where_predicates = where_clause.map(|clause| &clause.predicates);
652 Ok(quote! {
653 #[allow(deprecated)]
656 #[automatically_derived]
659 impl #impl_generics #zerocopy_crate::util::macro_util::core_reexport::cmp::PartialEq for #type_ident #ty_generics
660 where
661 Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
662 #where_predicates
663 {
664 fn eq(&self, other: &Self) -> bool {
665 #zerocopy_crate::util::macro_util::core_reexport::cmp::PartialEq::eq(
666 #zerocopy_crate::IntoBytes::as_bytes(self),
667 #zerocopy_crate::IntoBytes::as_bytes(other),
668 )
669 }
670 }
671
672 #[allow(deprecated)]
675 #[automatically_derived]
678 impl #impl_generics #zerocopy_crate::util::macro_util::core_reexport::cmp::Eq for #type_ident #ty_generics
679 where
680 Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
681 #where_predicates
682 {
683 }
684 })
685}
686
687fn derive_split_at_inner(
688 ast: &DeriveInput,
689 _top_level: Trait,
690 zerocopy_crate: &Path,
691) -> Result<TokenStream, Error> {
692 let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
693
694 match &ast.data {
695 Data::Struct(_) => {}
696 Data::Enum(_) | Data::Union(_) => {
697 return Err(Error::new(Span::call_site(), "can only be applied to structs"));
698 }
699 };
700
701 if repr.get_packed().is_some() {
702 return Err(Error::new(Span::call_site(), "must not have #[repr(packed)] attribute"));
703 }
704
705 let fields = ast.data.fields();
706 let trailing_field = if let Some(((_, _, trailing_field), _)) = fields.split_last() {
707 trailing_field
708 } else {
709 return Err(Error::new(Span::call_site(), "must at least one field"));
710 };
711
712 Ok(ImplBlockBuilder::new(
715 ast,
716 &ast.data,
717 Trait::SplitAt,
718 FieldBounds::TRAILING_SELF,
719 zerocopy_crate,
720 )
721 .inner_extras(quote! {
722 type Elem = <#trailing_field as ::zerocopy::SplitAt>::Elem;
723 })
724 .build())
725}
726
727fn derive_try_from_bytes_struct(
730 ast: &DeriveInput,
731 strct: &DataStruct,
732 top_level: Trait,
733 zerocopy_crate: &Path,
734) -> Result<TokenStream, Error> {
735 let extras =
736 try_gen_trivial_is_bit_valid(ast, top_level, zerocopy_crate).unwrap_or_else(|| {
737 let fields = strct.fields();
738 let field_names = fields.iter().map(|(_vis, name, _ty)| name);
739 let field_tys = fields.iter().map(|(_vis, _name, ty)| ty);
740 quote!(
741 fn is_bit_valid<___ZerocopyAliasing>(
747 mut candidate: #zerocopy_crate::Maybe<Self, ___ZerocopyAliasing>,
748 ) -> #zerocopy_crate::util::macro_util::core_reexport::primitive::bool
749 where
750 ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference,
751 {
752 use #zerocopy_crate::util::macro_util::core_reexport;
753
754 true #(&& {
755 let field_candidate = unsafe {
763 let project = |slf: core_reexport::ptr::NonNull<Self>| {
764 let slf = slf.as_ptr();
765 let field = core_reexport::ptr::addr_of_mut!((*slf).#field_names);
766 unsafe { core_reexport::ptr::NonNull::new_unchecked(field) }
774 };
775
776 candidate.reborrow().cast_unsized_unchecked(project)
777 };
778
779 <#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate)
780 })*
781 }
782 )
783 });
784 Ok(ImplBlockBuilder::new(
785 ast,
786 strct,
787 Trait::TryFromBytes,
788 FieldBounds::ALL_SELF,
789 zerocopy_crate,
790 )
791 .inner_extras(extras)
792 .build())
793}
794
795fn derive_try_from_bytes_union(
798 ast: &DeriveInput,
799 unn: &DataUnion,
800 top_level: Trait,
801 zerocopy_crate: &Path,
802) -> TokenStream {
803 let field_type_trait_bounds =
805 FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]);
806 let extras =
807 try_gen_trivial_is_bit_valid(ast, top_level, zerocopy_crate).unwrap_or_else(|| {
808 let fields = unn.fields();
809 let field_names = fields.iter().map(|(_vis, name, _ty)| name);
810 let field_tys = fields.iter().map(|(_vis, _name, ty)| ty);
811 quote!(
812 fn is_bit_valid<___ZerocopyAliasing>(
818 mut candidate: #zerocopy_crate::Maybe<'_, Self,___ZerocopyAliasing>
819 ) -> #zerocopy_crate::util::macro_util::core_reexport::primitive::bool
820 where
821 ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference,
822 {
823 use #zerocopy_crate::util::macro_util::core_reexport;
824
825 false #(|| {
826 let field_candidate = unsafe {
834 let project = |slf: core_reexport::ptr::NonNull<Self>| {
835 let slf = slf.as_ptr();
836 let field = core_reexport::ptr::addr_of_mut!((*slf).#field_names);
837 unsafe { core_reexport::ptr::NonNull::new_unchecked(field) }
845 };
846
847 candidate.reborrow().cast_unsized_unchecked(project)
848 };
849
850 <#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate)
851 })*
852 }
853 )
854 });
855 ImplBlockBuilder::new(ast, unn, Trait::TryFromBytes, field_type_trait_bounds, zerocopy_crate)
856 .inner_extras(extras)
857 .build()
858}
859
860fn derive_try_from_bytes_enum(
861 ast: &DeriveInput,
862 enm: &DataEnum,
863 top_level: Trait,
864 zerocopy_crate: &Path,
865) -> Result<TokenStream, Error> {
866 let repr = EnumRepr::from_attrs(&ast.attrs)?;
867
868 let could_be_from_bytes = enum_size_from_repr(&repr)
874 .map(|size| enm.fields().is_empty() && enm.variants.len() == 1usize << size)
875 .unwrap_or(false);
876
877 let trivial_is_bit_valid = try_gen_trivial_is_bit_valid(ast, top_level, zerocopy_crate);
878 let extra = match (trivial_is_bit_valid, could_be_from_bytes) {
879 (Some(is_bit_valid), _) => is_bit_valid,
880 (None, true) => unsafe { gen_trivial_is_bit_valid_unchecked(zerocopy_crate) },
883 (None, false) => {
884 r#enum::derive_is_bit_valid(&ast.ident, &repr, &ast.generics, enm, zerocopy_crate)?
885 }
886 };
887
888 Ok(ImplBlockBuilder::new(ast, enm, Trait::TryFromBytes, FieldBounds::ALL_SELF, zerocopy_crate)
889 .inner_extras(extra)
890 .build())
891}
892
893fn try_gen_trivial_is_bit_valid(
915 ast: &DeriveInput,
916 top_level: Trait,
917 zerocopy_crate: &Path,
918) -> Option<proc_macro2::TokenStream> {
919 if top_level == Trait::FromBytes && ast.generics.params.is_empty() {
928 Some(quote!(
929 fn is_bit_valid<___ZerocopyAliasing>(
931 _candidate: #zerocopy_crate::Maybe<Self, ___ZerocopyAliasing>,
932 ) -> #zerocopy_crate::util::macro_util::core_reexport::primitive::bool
933 where
934 ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference,
935 {
936 if false {
937 fn assert_is_from_bytes<T>()
938 where
939 T: #zerocopy_crate::FromBytes,
940 T: ?#zerocopy_crate::util::macro_util::core_reexport::marker::Sized,
941 {
942 }
943
944 assert_is_from_bytes::<Self>();
945 }
946
947 true
951 }
952 ))
953 } else {
954 None
955 }
956}
957
958unsafe fn gen_trivial_is_bit_valid_unchecked(zerocopy_crate: &Path) -> proc_macro2::TokenStream {
970 quote!(
971 fn is_bit_valid<___ZerocopyAliasing>(
974 _candidate: #zerocopy_crate::Maybe<Self, ___ZerocopyAliasing>,
975 ) -> #zerocopy_crate::util::macro_util::core_reexport::primitive::bool
976 where
977 ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference,
978 {
979 true
980 }
981 )
982}
983
984fn derive_from_zeros_struct(
987 ast: &DeriveInput,
988 strct: &DataStruct,
989 zerocopy_crate: &Path,
990) -> TokenStream {
991 ImplBlockBuilder::new(ast, strct, Trait::FromZeros, FieldBounds::ALL_SELF, zerocopy_crate)
992 .build()
993}
994
995fn find_zero_variant(enm: &DataEnum) -> Result<usize, bool> {
1001 let mut next_negative_discriminant = Some(0);
1009
1010 let mut has_unknown_discriminants = false;
1017
1018 for (i, v) in enm.variants.iter().enumerate() {
1019 match v.discriminant.as_ref() {
1020 None => {
1022 match next_negative_discriminant.as_mut() {
1023 Some(0) => return Ok(i),
1024 Some(n) => *n -= 1,
1026 None => (),
1027 }
1028 }
1029 Some((_, Expr::Lit(ExprLit { lit: Lit::Int(int), .. }))) => {
1031 match int.base10_parse::<u128>().ok() {
1032 Some(0) => return Ok(i),
1033 Some(_) => next_negative_discriminant = None,
1034 None => {
1035 has_unknown_discriminants = true;
1037 next_negative_discriminant = None;
1038 }
1039 }
1040 }
1041 Some((_, Expr::Unary(ExprUnary { op: UnOp::Neg(_), expr, .. }))) => match &**expr {
1043 Expr::Lit(ExprLit { lit: Lit::Int(int), .. }) => {
1044 match int.base10_parse::<u128>().ok() {
1045 Some(0) => return Ok(i),
1046 Some(x) => next_negative_discriminant = Some(x - 1),
1048 None => {
1049 has_unknown_discriminants = true;
1052 next_negative_discriminant = None;
1053 }
1054 }
1055 }
1056 _ => {
1058 has_unknown_discriminants = true;
1059 next_negative_discriminant = None;
1060 }
1061 },
1062 _ => {
1064 has_unknown_discriminants = true;
1065 next_negative_discriminant = None;
1066 }
1067 }
1068 }
1069
1070 Err(has_unknown_discriminants)
1071}
1072
1073fn derive_from_zeros_enum(
1077 ast: &DeriveInput,
1078 enm: &DataEnum,
1079 zerocopy_crate: &Path,
1080) -> Result<TokenStream, Error> {
1081 let repr = EnumRepr::from_attrs(&ast.attrs)?;
1082
1083 match repr {
1086 Repr::Compound(
1087 Spanned { t: CompoundRepr::C | CompoundRepr::Primitive(_), span: _ },
1088 _,
1089 ) => {}
1090 Repr::Transparent(_)
1091 | Repr::Compound(Spanned { t: CompoundRepr::Rust, span: _ }, _) => return Err(Error::new(Span::call_site(), "must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout")),
1092 }
1093
1094 let zero_variant = match find_zero_variant(enm) {
1095 Ok(index) => enm.variants.iter().nth(index).unwrap(),
1096 Err(true) => {
1098 return Err(Error::new_spanned(
1099 ast,
1100 "FromZeros only supported on enums with a variant that has a discriminant of `0`\n\
1101 help: This enum has discriminants which are not literal integers. One of those may \
1102 define or imply which variant has a discriminant of zero. Use a literal integer to \
1103 define or imply the variant with a discriminant of zero.",
1104 ));
1105 }
1106 Err(false) => {
1108 return Err(Error::new_spanned(
1109 ast,
1110 "FromZeros only supported on enums with a variant that has a discriminant of `0`",
1111 ));
1112 }
1113 };
1114
1115 let explicit_bounds = zero_variant
1116 .fields
1117 .iter()
1118 .map(|field| {
1119 let ty = &field.ty;
1120 parse_quote! { #ty: #zerocopy_crate::FromZeros }
1121 })
1122 .collect::<Vec<WherePredicate>>();
1123
1124 Ok(ImplBlockBuilder::new(
1125 ast,
1126 enm,
1127 Trait::FromZeros,
1128 FieldBounds::Explicit(explicit_bounds),
1129 zerocopy_crate,
1130 )
1131 .build())
1132}
1133
1134fn derive_from_zeros_union(
1137 ast: &DeriveInput,
1138 unn: &DataUnion,
1139 zerocopy_crate: &Path,
1140) -> TokenStream {
1141 let field_type_trait_bounds =
1144 FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]);
1145 ImplBlockBuilder::new(ast, unn, Trait::FromZeros, field_type_trait_bounds, zerocopy_crate)
1146 .build()
1147}
1148
1149fn derive_from_bytes_struct(
1152 ast: &DeriveInput,
1153 strct: &DataStruct,
1154 zerocopy_crate: &Path,
1155) -> TokenStream {
1156 ImplBlockBuilder::new(ast, strct, Trait::FromBytes, FieldBounds::ALL_SELF, zerocopy_crate)
1157 .build()
1158}
1159
1160fn derive_from_bytes_enum(
1175 ast: &DeriveInput,
1176 enm: &DataEnum,
1177 zerocopy_crate: &Path,
1178) -> Result<TokenStream, Error> {
1179 let repr = EnumRepr::from_attrs(&ast.attrs)?;
1180
1181 let variants_required = 1usize << enum_size_from_repr(&repr)?;
1182 if enm.variants.len() != variants_required {
1183 return Err(Error::new_spanned(
1184 ast,
1185 format!(
1186 "FromBytes only supported on {} enum with {} variants",
1187 repr.repr_type_name(),
1188 variants_required
1189 ),
1190 ));
1191 }
1192
1193 Ok(ImplBlockBuilder::new(ast, enm, Trait::FromBytes, FieldBounds::ALL_SELF, zerocopy_crate)
1194 .build())
1195}
1196
1197fn enum_size_from_repr(repr: &EnumRepr) -> Result<usize, Error> {
1199 use {CompoundRepr::*, PrimitiveRepr::*, Repr::*};
1200 match repr {
1201 Transparent(span)
1202 | Compound(
1203 Spanned { t: C | Rust | Primitive(U32 | I32 | U64 | I64 | Usize | Isize), span },
1204 _,
1205 ) => Err(Error::new(*span, "`FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`")),
1206 Compound(Spanned { t: Primitive(U8 | I8), span: _ }, _align) => Ok(8),
1207 Compound(Spanned { t: Primitive(U16 | I16), span: _ }, _align) => Ok(16),
1208 }
1209}
1210
1211fn derive_from_bytes_union(
1214 ast: &DeriveInput,
1215 unn: &DataUnion,
1216 zerocopy_crate: &Path,
1217) -> TokenStream {
1218 let field_type_trait_bounds =
1221 FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]);
1222 ImplBlockBuilder::new(ast, unn, Trait::FromBytes, field_type_trait_bounds, zerocopy_crate)
1223 .build()
1224}
1225
1226fn derive_into_bytes_struct(
1227 ast: &DeriveInput,
1228 strct: &DataStruct,
1229 zerocopy_crate: &Path,
1230) -> Result<TokenStream, Error> {
1231 let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
1232
1233 let is_transparent = repr.is_transparent();
1234 let is_c = repr.is_c();
1235 let is_packed_1 = repr.is_packed_1();
1236 let num_fields = strct.fields().len();
1237
1238 let (padding_check, require_unaligned_fields) = if is_transparent || is_packed_1 {
1239 (None, false)
1256 } else if is_c && !repr.is_align_gt_1() && num_fields <= 1 {
1257 (None, false)
1261 } else if ast.generics.params.is_empty() {
1262 (Some(PaddingCheck::Struct), false)
1275 } else if is_c && !repr.is_align_gt_1() {
1276 (None, true)
1285 } else {
1286 return Err(Error::new(Span::call_site(), "must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout"));
1287 };
1288
1289 let field_bounds = if require_unaligned_fields {
1290 FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Unaligned)])
1291 } else {
1292 FieldBounds::ALL_SELF
1293 };
1294
1295 Ok(ImplBlockBuilder::new(ast, strct, Trait::IntoBytes, field_bounds, zerocopy_crate)
1296 .padding_check(padding_check)
1297 .build())
1298}
1299
1300fn derive_into_bytes_enum(
1306 ast: &DeriveInput,
1307 enm: &DataEnum,
1308 zerocopy_crate: &Path,
1309) -> Result<TokenStream, Error> {
1310 let repr = EnumRepr::from_attrs(&ast.attrs)?;
1311 if !repr.is_c() && !repr.is_primitive() {
1312 return Err(Error::new(Span::call_site(), "must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout"));
1313 }
1314
1315 let tag_type_definition = r#enum::generate_tag_enum(&repr, enm);
1316 Ok(ImplBlockBuilder::new(ast, enm, Trait::IntoBytes, FieldBounds::ALL_SELF, zerocopy_crate)
1317 .padding_check(PaddingCheck::Enum { tag_type_definition })
1318 .build())
1319}
1320
1321fn derive_into_bytes_union(
1326 ast: &DeriveInput,
1327 unn: &DataUnion,
1328 zerocopy_crate: &Path,
1329) -> Result<TokenStream, Error> {
1330 let cfg_compile_error = if cfg!(zerocopy_derive_union_into_bytes) {
1339 quote!()
1340 } else {
1341 let error_message = "requires --cfg zerocopy_derive_union_into_bytes;
1342please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802";
1343 quote!(
1344 const _: () = {
1345 #[cfg(not(zerocopy_derive_union_into_bytes))]
1346 #zerocopy_crate::util::macro_util::core_reexport::compile_error!(#error_message);
1347 };
1348 )
1349 };
1350
1351 if !ast.generics.params.is_empty() {
1353 return Err(Error::new(Span::call_site(), "unsupported on types with type parameters"));
1354 }
1355
1356 let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
1361 if !repr.is_c() && !repr.is_transparent() && !repr.is_packed_1() {
1362 return Err(Error::new(
1363 Span::call_site(),
1364 "must be #[repr(C)], #[repr(packed)], or #[repr(transparent)]",
1365 ));
1366 }
1367
1368 let impl_block =
1369 ImplBlockBuilder::new(ast, unn, Trait::IntoBytes, FieldBounds::ALL_SELF, zerocopy_crate)
1370 .padding_check(PaddingCheck::Union)
1371 .build();
1372 Ok(quote!(#cfg_compile_error #impl_block))
1373}
1374
1375fn derive_unaligned_struct(
1381 ast: &DeriveInput,
1382 strct: &DataStruct,
1383 zerocopy_crate: &Path,
1384) -> Result<TokenStream, Error> {
1385 let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
1386 repr.unaligned_validate_no_align_gt_1()?;
1387
1388 let field_bounds = if repr.is_packed_1() {
1389 FieldBounds::None
1390 } else if repr.is_c() || repr.is_transparent() {
1391 FieldBounds::ALL_SELF
1392 } else {
1393 return Err(Error::new(Span::call_site(), "must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment"));
1394 };
1395
1396 Ok(ImplBlockBuilder::new(ast, strct, Trait::Unaligned, field_bounds, zerocopy_crate).build())
1397}
1398
1399fn derive_unaligned_enum(
1403 ast: &DeriveInput,
1404 enm: &DataEnum,
1405 zerocopy_crate: &Path,
1406) -> Result<TokenStream, Error> {
1407 let repr = EnumRepr::from_attrs(&ast.attrs)?;
1408 repr.unaligned_validate_no_align_gt_1()?;
1409
1410 if !repr.is_u8() && !repr.is_i8() {
1411 return Err(Error::new(Span::call_site(), "must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment"));
1412 }
1413
1414 Ok(ImplBlockBuilder::new(ast, enm, Trait::Unaligned, FieldBounds::ALL_SELF, zerocopy_crate)
1415 .build())
1416}
1417
1418fn derive_unaligned_union(
1424 ast: &DeriveInput,
1425 unn: &DataUnion,
1426 zerocopy_crate: &Path,
1427) -> Result<TokenStream, Error> {
1428 let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
1429 repr.unaligned_validate_no_align_gt_1()?;
1430
1431 let field_type_trait_bounds = if repr.is_packed_1() {
1432 FieldBounds::None
1433 } else if repr.is_c() || repr.is_transparent() {
1434 FieldBounds::ALL_SELF
1435 } else {
1436 return Err(Error::new(Span::call_site(), "must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment"));
1437 };
1438
1439 Ok(ImplBlockBuilder::new(ast, unn, Trait::Unaligned, field_type_trait_bounds, zerocopy_crate)
1440 .build())
1441}
1442
1443enum PaddingCheck {
1446 Struct,
1449 Union,
1451 Enum { tag_type_definition: TokenStream },
1456}
1457
1458impl PaddingCheck {
1459 fn validator_macro_ident(&self) -> Ident {
1462 let s = match self {
1463 PaddingCheck::Struct => "struct_has_padding",
1464 PaddingCheck::Union => "union_has_padding",
1465 PaddingCheck::Enum { .. } => "enum_has_padding",
1466 };
1467
1468 Ident::new(s, Span::call_site())
1469 }
1470
1471 fn validator_macro_context(&self) -> Option<&TokenStream> {
1474 match self {
1475 PaddingCheck::Struct | PaddingCheck::Union => None,
1476 PaddingCheck::Enum { tag_type_definition } => Some(tag_type_definition),
1477 }
1478 }
1479}
1480
1481#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1482enum Trait {
1483 KnownLayout,
1484 Immutable,
1485 TryFromBytes,
1486 FromZeros,
1487 FromBytes,
1488 IntoBytes,
1489 Unaligned,
1490 Sized,
1491 ByteHash,
1492 ByteEq,
1493 SplitAt,
1494}
1495
1496impl ToTokens for Trait {
1497 fn to_tokens(&self, tokens: &mut TokenStream) {
1498 let s = match self {
1508 Trait::KnownLayout => "KnownLayout",
1509 Trait::Immutable => "Immutable",
1510 Trait::TryFromBytes => "TryFromBytes",
1511 Trait::FromZeros => "FromZeros",
1512 Trait::FromBytes => "FromBytes",
1513 Trait::IntoBytes => "IntoBytes",
1514 Trait::Unaligned => "Unaligned",
1515 Trait::Sized => "Sized",
1516 Trait::ByteHash => "ByteHash",
1517 Trait::ByteEq => "ByteEq",
1518 Trait::SplitAt => "SplitAt",
1519 };
1520 let ident = Ident::new(s, Span::call_site());
1521 tokens.extend(core::iter::once(TokenTree::Ident(ident)));
1522 }
1523}
1524
1525impl Trait {
1526 fn crate_path(&self, zerocopy_crate: &Path) -> Path {
1527 match self {
1528 Self::Sized => {
1529 parse_quote!(#zerocopy_crate::util::macro_util::core_reexport::marker::#self)
1530 }
1531 _ => parse_quote!(#zerocopy_crate::#self),
1532 }
1533 }
1534}
1535
1536#[derive(Debug, Eq, PartialEq)]
1537enum TraitBound {
1538 Slf,
1539 Other(Trait),
1540}
1541
1542enum FieldBounds<'a> {
1543 None,
1544 All(&'a [TraitBound]),
1545 Trailing(&'a [TraitBound]),
1546 Explicit(Vec<WherePredicate>),
1547}
1548
1549impl<'a> FieldBounds<'a> {
1550 const ALL_SELF: FieldBounds<'a> = FieldBounds::All(&[TraitBound::Slf]);
1551 const TRAILING_SELF: FieldBounds<'a> = FieldBounds::Trailing(&[TraitBound::Slf]);
1552}
1553
1554#[derive(Debug, Eq, PartialEq)]
1555enum SelfBounds<'a> {
1556 None,
1557 All(&'a [Trait]),
1558}
1559
1560#[allow(clippy::needless_lifetimes)]
1563impl<'a> SelfBounds<'a> {
1564 const SIZED: Self = Self::All(&[Trait::Sized]);
1565}
1566
1567fn normalize_bounds(slf: Trait, bounds: &[TraitBound]) -> impl '_ + Iterator<Item = Trait> {
1569 bounds.iter().map(move |bound| match bound {
1570 TraitBound::Slf => slf,
1571 TraitBound::Other(trt) => *trt,
1572 })
1573}
1574
1575struct ImplBlockBuilder<'a, D: DataExt> {
1576 input: &'a DeriveInput,
1577 data: &'a D,
1578 trt: Trait,
1579 field_type_trait_bounds: FieldBounds<'a>,
1580 zerocopy_crate: &'a Path,
1581 self_type_trait_bounds: SelfBounds<'a>,
1582 padding_check: Option<PaddingCheck>,
1583 inner_extras: Option<TokenStream>,
1584 outer_extras: Option<TokenStream>,
1585}
1586
1587impl<'a, D: DataExt> ImplBlockBuilder<'a, D> {
1588 fn new(
1589 input: &'a DeriveInput,
1590 data: &'a D,
1591 trt: Trait,
1592 field_type_trait_bounds: FieldBounds<'a>,
1593 zerocopy_crate: &'a Path,
1594 ) -> Self {
1595 Self {
1596 input,
1597 data,
1598 trt,
1599 field_type_trait_bounds,
1600 zerocopy_crate,
1601 self_type_trait_bounds: SelfBounds::None,
1602 padding_check: None,
1603 inner_extras: None,
1604 outer_extras: None,
1605 }
1606 }
1607
1608 fn self_type_trait_bounds(mut self, self_type_trait_bounds: SelfBounds<'a>) -> Self {
1609 self.self_type_trait_bounds = self_type_trait_bounds;
1610 self
1611 }
1612
1613 fn padding_check<P: Into<Option<PaddingCheck>>>(mut self, padding_check: P) -> Self {
1614 self.padding_check = padding_check.into();
1615 self
1616 }
1617
1618 fn inner_extras(mut self, inner_extras: TokenStream) -> Self {
1619 self.inner_extras = Some(inner_extras);
1620 self
1621 }
1622
1623 fn outer_extras<T: Into<Option<TokenStream>>>(mut self, outer_extras: T) -> Self {
1624 self.outer_extras = outer_extras.into();
1625 self
1626 }
1627
1628 fn build(self) -> TokenStream {
1629 let type_ident = &self.input.ident;
1689 let trait_path = self.trt.crate_path(self.zerocopy_crate);
1690 let fields = self.data.fields();
1691 let variants = self.data.variants();
1692 let tag = self.data.tag();
1693 let zerocopy_crate = self.zerocopy_crate;
1694
1695 fn bound_tt(
1696 ty: &Type,
1697 traits: impl Iterator<Item = Trait>,
1698 zerocopy_crate: &Path,
1699 ) -> WherePredicate {
1700 let traits = traits.map(|t| t.crate_path(zerocopy_crate));
1701 parse_quote!(#ty: #(#traits)+*)
1702 }
1703 let field_type_bounds: Vec<_> = match (self.field_type_trait_bounds, &fields[..]) {
1704 (FieldBounds::All(traits), _) => fields
1705 .iter()
1706 .map(|(_vis, _name, ty)| {
1707 bound_tt(ty, normalize_bounds(self.trt, traits), zerocopy_crate)
1708 })
1709 .collect(),
1710 (FieldBounds::None, _) | (FieldBounds::Trailing(..), []) => vec![],
1711 (FieldBounds::Trailing(traits), [.., last]) => {
1712 vec![bound_tt(last.2, normalize_bounds(self.trt, traits), zerocopy_crate)]
1713 }
1714 (FieldBounds::Explicit(bounds), _) => bounds,
1715 };
1716
1717 #[allow(unstable_name_collisions)] let padding_check_bound = self
1720 .padding_check
1721 .and_then(|check| (!fields.is_empty()).then_some(check))
1722 .map(|check| {
1723 let variant_types = variants.iter().map(|var| {
1724 let types = var.iter().map(|(_vis, _name, ty)| ty);
1725 quote!([#(#types),*])
1726 });
1727 let validator_context = check.validator_macro_context();
1728 let validator_macro = check.validator_macro_ident();
1729 let t = tag.iter();
1730 parse_quote! {
1731 (): #zerocopy_crate::util::macro_util::PaddingFree<
1732 Self,
1733 {
1734 #validator_context
1735 #zerocopy_crate::#validator_macro!(Self, #(#t,)* #(#variant_types),*)
1736 }
1737 >
1738 }
1739 });
1740
1741 let self_bounds: Option<WherePredicate> = match self.self_type_trait_bounds {
1742 SelfBounds::None => None,
1743 SelfBounds::All(traits) => {
1744 Some(bound_tt(&parse_quote!(Self), traits.iter().copied(), zerocopy_crate))
1745 }
1746 };
1747
1748 let bounds = self
1749 .input
1750 .generics
1751 .where_clause
1752 .as_ref()
1753 .map(|where_clause| where_clause.predicates.iter())
1754 .into_iter()
1755 .flatten()
1756 .chain(field_type_bounds.iter())
1757 .chain(padding_check_bound.iter())
1758 .chain(self_bounds.iter());
1759
1760 let params = self.input.generics.params.clone().into_iter().map(|mut param| {
1762 match &mut param {
1763 GenericParam::Type(ty) => ty.default = None,
1764 GenericParam::Const(cnst) => cnst.default = None,
1765 GenericParam::Lifetime(_) => {}
1766 }
1767 quote!(#param)
1768 });
1769
1770 let param_idents = self.input.generics.params.iter().map(|param| match param {
1773 GenericParam::Type(ty) => {
1774 let ident = &ty.ident;
1775 quote!(#ident)
1776 }
1777 GenericParam::Lifetime(l) => {
1778 let ident = &l.lifetime;
1779 quote!(#ident)
1780 }
1781 GenericParam::Const(cnst) => {
1782 let ident = &cnst.ident;
1783 quote!({#ident})
1784 }
1785 });
1786
1787 let inner_extras = self.inner_extras;
1788 let impl_tokens = quote! {
1789 #[allow(deprecated)]
1792 #[automatically_derived]
1795 unsafe impl < #(#params),* > #trait_path for #type_ident < #(#param_idents),* >
1796 where
1797 #(#bounds,)*
1798 {
1799 fn only_derive_is_allowed_to_implement_this_trait() {}
1800
1801 #inner_extras
1802 }
1803 };
1804
1805 if let Some(outer_extras) = self.outer_extras {
1806 quote! {
1809 const _: () = {
1810 #impl_tokens
1811
1812 #outer_extras
1813 };
1814 }
1815 } else {
1816 impl_tokens
1817 }
1818 }
1819}
1820
1821#[allow(unused)]
1829trait BoolExt {
1830 fn then_some<T>(self, t: T) -> Option<T>;
1831}
1832
1833impl BoolExt for bool {
1834 fn then_some<T>(self, t: T) -> Option<T> {
1835 if self {
1836 Some(t)
1837 } else {
1838 None
1839 }
1840 }
1841}