1 #![allow(unused_imports)]
2 use std::{cmp, convert::TryFrom};
3 
4 use proc_macro2::{Ident, Span, TokenStream, TokenTree};
5 use quote::{quote, quote_spanned, ToTokens};
6 use syn::{
7   parse::{Parse, ParseStream, Parser},
8   punctuated::Punctuated,
9   spanned::Spanned,
10   Result, *,
11 };
12 
13 macro_rules! bail {
14   ($msg:expr $(,)?) => {
15     return Err(Error::new(Span::call_site(), &$msg[..]))
16   };
17 
18   ( $msg:expr => $span_to_blame:expr $(,)? ) => {
19     return Err(Error::new_spanned(&$span_to_blame, $msg))
20   };
21 }
22 
23 pub trait Derivable {
ident(input: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>24   fn ident(input: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>;
implies_trait(_crate_name: &TokenStream) -> Option<TokenStream>25   fn implies_trait(_crate_name: &TokenStream) -> Option<TokenStream> {
26     None
27   }
asserts( _input: &DeriveInput, _crate_name: &TokenStream, ) -> Result<TokenStream>28   fn asserts(
29     _input: &DeriveInput, _crate_name: &TokenStream,
30   ) -> Result<TokenStream> {
31     Ok(quote!())
32   }
check_attributes(_ty: &Data, _attributes: &[Attribute]) -> Result<()>33   fn check_attributes(_ty: &Data, _attributes: &[Attribute]) -> Result<()> {
34     Ok(())
35   }
trait_impl( _input: &DeriveInput, _crate_name: &TokenStream, ) -> Result<(TokenStream, TokenStream)>36   fn trait_impl(
37     _input: &DeriveInput, _crate_name: &TokenStream,
38   ) -> Result<(TokenStream, TokenStream)> {
39     Ok((quote!(), quote!()))
40   }
requires_where_clause() -> bool41   fn requires_where_clause() -> bool {
42     true
43   }
explicit_bounds_attribute_name() -> Option<&'static str>44   fn explicit_bounds_attribute_name() -> Option<&'static str> {
45     None
46   }
47 }
48 
49 pub struct Pod;
50 
51 impl Derivable for Pod {
ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>52   fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
53     Ok(syn::parse_quote!(#crate_name::Pod))
54   }
55 
asserts( input: &DeriveInput, crate_name: &TokenStream, ) -> Result<TokenStream>56   fn asserts(
57     input: &DeriveInput, crate_name: &TokenStream,
58   ) -> Result<TokenStream> {
59     let repr = get_repr(&input.attrs)?;
60 
61     let completly_packed =
62       repr.packed == Some(1) || repr.repr == Repr::Transparent;
63 
64     if !completly_packed && !input.generics.params.is_empty() {
65       bail!("\
66         Pod requires cannot be derived for non-packed types containing \
67         generic parameters because the padding requirements can't be verified \
68         for generic non-packed structs\
69       " => input.generics.params.first().unwrap());
70     }
71 
72     match &input.data {
73       Data::Struct(_) => {
74         let assert_no_padding = if !completly_packed {
75           Some(generate_assert_no_padding(input)?)
76         } else {
77           None
78         };
79         let assert_fields_are_pod =
80           generate_fields_are_trait(input, Self::ident(input, crate_name)?)?;
81 
82         Ok(quote!(
83           #assert_no_padding
84           #assert_fields_are_pod
85         ))
86       }
87       Data::Enum(_) => bail!("Deriving Pod is not supported for enums"),
88       Data::Union(_) => bail!("Deriving Pod is not supported for unions"),
89     }
90   }
91 
check_attributes(_ty: &Data, attributes: &[Attribute]) -> Result<()>92   fn check_attributes(_ty: &Data, attributes: &[Attribute]) -> Result<()> {
93     let repr = get_repr(attributes)?;
94     match repr.repr {
95       Repr::C => Ok(()),
96       Repr::Transparent => Ok(()),
97       _ => {
98         bail!("Pod requires the type to be #[repr(C)] or #[repr(transparent)]")
99       }
100     }
101   }
102 }
103 
104 pub struct AnyBitPattern;
105 
106 impl Derivable for AnyBitPattern {
ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>107   fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
108     Ok(syn::parse_quote!(#crate_name::AnyBitPattern))
109   }
110 
implies_trait(crate_name: &TokenStream) -> Option<TokenStream>111   fn implies_trait(crate_name: &TokenStream) -> Option<TokenStream> {
112     Some(quote!(#crate_name::Zeroable))
113   }
114 
asserts( input: &DeriveInput, crate_name: &TokenStream, ) -> Result<TokenStream>115   fn asserts(
116     input: &DeriveInput, crate_name: &TokenStream,
117   ) -> Result<TokenStream> {
118     match &input.data {
119       Data::Union(_) => Ok(quote!()), // unions are always `AnyBitPattern`
120       Data::Struct(_) => {
121         generate_fields_are_trait(input, Self::ident(input, crate_name)?)
122       }
123       Data::Enum(_) => {
124         bail!("Deriving AnyBitPattern is not supported for enums")
125       }
126     }
127   }
128 }
129 
130 pub struct Zeroable;
131 
132 impl Derivable for Zeroable {
ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>133   fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
134     Ok(syn::parse_quote!(#crate_name::Zeroable))
135   }
136 
check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()>137   fn check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()> {
138     let repr = get_repr(attributes)?;
139     match ty {
140       Data::Struct(_) => Ok(()),
141       Data::Enum(DataEnum { variants, .. }) => {
142         if !repr.repr.is_integer() {
143           bail!("Zeroable requires the enum to be an explicit #[repr(Int)]")
144         }
145 
146         if variants.iter().any(|variant| !variant.fields.is_empty()) {
147           bail!("Only fieldless enums are supported for Zeroable")
148         }
149 
150         let iter = VariantDiscriminantIterator::new(variants.iter());
151         let mut has_zero_variant = false;
152         for res in iter {
153           let discriminant = res?;
154           if discriminant == 0 {
155             has_zero_variant = true;
156             break;
157           }
158         }
159         if !has_zero_variant {
160           bail!("No variant's discriminant is 0")
161         }
162 
163         Ok(())
164       }
165       Data::Union(_) => Ok(()),
166     }
167   }
168 
asserts( input: &DeriveInput, crate_name: &TokenStream, ) -> Result<TokenStream>169   fn asserts(
170     input: &DeriveInput, crate_name: &TokenStream,
171   ) -> Result<TokenStream> {
172     match &input.data {
173       Data::Union(_) => Ok(quote!()), // unions are always `Zeroable`
174       Data::Struct(_) => {
175         generate_fields_are_trait(input, Self::ident(input, crate_name)?)
176       }
177       Data::Enum(_) => Ok(quote!()),
178     }
179   }
180 
explicit_bounds_attribute_name() -> Option<&'static str>181   fn explicit_bounds_attribute_name() -> Option<&'static str> {
182     Some("zeroable")
183   }
184 }
185 
186 pub struct NoUninit;
187 
188 impl Derivable for NoUninit {
ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>189   fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
190     Ok(syn::parse_quote!(#crate_name::NoUninit))
191   }
192 
check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()>193   fn check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()> {
194     let repr = get_repr(attributes)?;
195     match ty {
196       Data::Struct(_) => match repr.repr {
197         Repr::C | Repr::Transparent => Ok(()),
198         _ => bail!("NoUninit requires the struct to be #[repr(C)] or #[repr(transparent)]"),
199       },
200       Data::Enum(_) => if repr.repr.is_integer() {
201         Ok(())
202       } else {
203         bail!("NoUninit requires the enum to be an explicit #[repr(Int)]")
204       },
205       Data::Union(_) => bail!("NoUninit can only be derived on enums and structs")
206     }
207   }
208 
asserts( input: &DeriveInput, crate_name: &TokenStream, ) -> Result<TokenStream>209   fn asserts(
210     input: &DeriveInput, crate_name: &TokenStream,
211   ) -> Result<TokenStream> {
212     if !input.generics.params.is_empty() {
213       bail!("NoUninit cannot be derived for structs containing generic parameters because the padding requirements can't be verified for generic structs");
214     }
215 
216     match &input.data {
217       Data::Struct(DataStruct { .. }) => {
218         let assert_no_padding = generate_assert_no_padding(&input)?;
219         let assert_fields_are_no_padding =
220           generate_fields_are_trait(&input, Self::ident(input, crate_name)?)?;
221 
222         Ok(quote!(
223             #assert_no_padding
224             #assert_fields_are_no_padding
225         ))
226       }
227       Data::Enum(DataEnum { variants, .. }) => {
228         if variants.iter().any(|variant| !variant.fields.is_empty()) {
229           bail!("Only fieldless enums are supported for NoUninit")
230         } else {
231           Ok(quote!())
232         }
233       }
234       Data::Union(_) => bail!("NoUninit cannot be derived for unions"), /* shouldn't be possible since we already error in attribute check for this case */
235     }
236   }
237 
trait_impl( _input: &DeriveInput, _crate_name: &TokenStream, ) -> Result<(TokenStream, TokenStream)>238   fn trait_impl(
239     _input: &DeriveInput, _crate_name: &TokenStream,
240   ) -> Result<(TokenStream, TokenStream)> {
241     Ok((quote!(), quote!()))
242   }
243 }
244 
245 pub struct CheckedBitPattern;
246 
247 impl Derivable for CheckedBitPattern {
ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>248   fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
249     Ok(syn::parse_quote!(#crate_name::CheckedBitPattern))
250   }
251 
check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()>252   fn check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()> {
253     let repr = get_repr(attributes)?;
254     match ty {
255       Data::Struct(_) => match repr.repr {
256         Repr::C | Repr::Transparent => Ok(()),
257         _ => bail!("CheckedBitPattern derive requires the struct to be #[repr(C)] or #[repr(transparent)]"),
258       },
259       Data::Enum(DataEnum { variants,.. }) => {
260         if !enum_has_fields(variants.iter()){
261           if repr.repr.is_integer() {
262             Ok(())
263           } else {
264             bail!("CheckedBitPattern requires the enum to be an explicit #[repr(Int)]")
265           }
266         } else if matches!(repr.repr, Repr::Rust) {
267           bail!("CheckedBitPattern requires an explicit repr annotation because `repr(Rust)` doesn't have a specified type layout")
268         } else {
269           Ok(())
270         }
271       }
272       Data::Union(_) => bail!("CheckedBitPattern can only be derived on enums and structs")
273     }
274   }
275 
asserts( input: &DeriveInput, crate_name: &TokenStream, ) -> Result<TokenStream>276   fn asserts(
277     input: &DeriveInput, crate_name: &TokenStream,
278   ) -> Result<TokenStream> {
279     if !input.generics.params.is_empty() {
280       bail!("CheckedBitPattern cannot be derived for structs containing generic parameters");
281     }
282 
283     match &input.data {
284       Data::Struct(DataStruct { .. }) => {
285         let assert_fields_are_maybe_pod =
286           generate_fields_are_trait(&input, Self::ident(input, crate_name)?)?;
287 
288         Ok(assert_fields_are_maybe_pod)
289       }
290       Data::Enum(_) => Ok(quote!()), /* nothing needed, already guaranteed
291                                        * OK by NoUninit */
292       Data::Union(_) => bail!("Internal error in CheckedBitPattern derive"), /* shouldn't be possible since we already error in attribute check for this case */
293     }
294   }
295 
trait_impl( input: &DeriveInput, crate_name: &TokenStream, ) -> Result<(TokenStream, TokenStream)>296   fn trait_impl(
297     input: &DeriveInput, crate_name: &TokenStream,
298   ) -> Result<(TokenStream, TokenStream)> {
299     match &input.data {
300       Data::Struct(DataStruct { fields, .. }) => {
301         generate_checked_bit_pattern_struct(
302           &input.ident,
303           fields,
304           &input.attrs,
305           crate_name,
306         )
307       }
308       Data::Enum(DataEnum { variants, .. }) => {
309         generate_checked_bit_pattern_enum(input, variants, crate_name)
310       }
311       Data::Union(_) => bail!("Internal error in CheckedBitPattern derive"), /* shouldn't be possible since we already error in attribute check for this case */
312     }
313   }
314 }
315 
316 pub struct TransparentWrapper;
317 
318 impl TransparentWrapper {
get_wrapper_type( attributes: &[Attribute], fields: &Fields, ) -> Option<TokenStream>319   fn get_wrapper_type(
320     attributes: &[Attribute], fields: &Fields,
321   ) -> Option<TokenStream> {
322     let transparent_param = get_simple_attr(attributes, "transparent");
323     transparent_param.map(|ident| ident.to_token_stream()).or_else(|| {
324       let mut types = get_field_types(&fields);
325       let first_type = types.next();
326       if let Some(_) = types.next() {
327         // can't guess param type if there is more than one field
328         return None;
329       } else {
330         first_type.map(|ty| ty.to_token_stream())
331       }
332     })
333   }
334 }
335 
336 impl Derivable for TransparentWrapper {
ident(input: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>337   fn ident(input: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
338     let fields = get_struct_fields(input)?;
339 
340     let ty = match Self::get_wrapper_type(&input.attrs, &fields) {
341       Some(ty) => ty,
342       None => bail!(
343         "\
344         when deriving TransparentWrapper for a struct with more than one field \
345         you need to specify the transparent field using #[transparent(T)]\
346       "
347       ),
348     };
349 
350     Ok(syn::parse_quote!(#crate_name::TransparentWrapper<#ty>))
351   }
352 
asserts( input: &DeriveInput, crate_name: &TokenStream, ) -> Result<TokenStream>353   fn asserts(
354     input: &DeriveInput, crate_name: &TokenStream,
355   ) -> Result<TokenStream> {
356     let (impl_generics, _ty_generics, where_clause) =
357       input.generics.split_for_impl();
358     let fields = get_struct_fields(input)?;
359     let wrapped_type = match Self::get_wrapper_type(&input.attrs, &fields) {
360       Some(wrapped_type) => wrapped_type.to_string(),
361       None => unreachable!(), /* other code will already reject this derive */
362     };
363     let mut wrapped_field_ty = None;
364     let mut nonwrapped_field_tys = vec![];
365     for field in fields.iter() {
366       let field_ty = &field.ty;
367       if field_ty.to_token_stream().to_string() == wrapped_type {
368         if wrapped_field_ty.is_some() {
369           bail!(
370             "TransparentWrapper can only have one field of the wrapped type"
371           );
372         }
373         wrapped_field_ty = Some(field_ty);
374       } else {
375         nonwrapped_field_tys.push(field_ty);
376       }
377     }
378     if let Some(wrapped_field_ty) = wrapped_field_ty {
379       Ok(quote!(
380         const _: () = {
381           #[repr(transparent)]
382           #[allow(clippy::multiple_bound_locations)]
383           struct AssertWrappedIsWrapped #impl_generics((u8, ::core::marker::PhantomData<#wrapped_field_ty>), #(#nonwrapped_field_tys),*) #where_clause;
384           fn assert_zeroable<Z: #crate_name::Zeroable>() {}
385           #[allow(clippy::multiple_bound_locations)]
386           fn check #impl_generics () #where_clause {
387             #(
388               assert_zeroable::<#nonwrapped_field_tys>();
389             )*
390           }
391         };
392       ))
393     } else {
394       bail!("TransparentWrapper must have one field of the wrapped type")
395     }
396   }
397 
check_attributes(_ty: &Data, attributes: &[Attribute]) -> Result<()>398   fn check_attributes(_ty: &Data, attributes: &[Attribute]) -> Result<()> {
399     let repr = get_repr(attributes)?;
400 
401     match repr.repr {
402       Repr::Transparent => Ok(()),
403       _ => {
404         bail!(
405           "TransparentWrapper requires the struct to be #[repr(transparent)]"
406         )
407       }
408     }
409   }
410 
requires_where_clause() -> bool411   fn requires_where_clause() -> bool {
412     false
413   }
414 }
415 
416 pub struct Contiguous;
417 
418 impl Derivable for Contiguous {
ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>419   fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
420     Ok(syn::parse_quote!(#crate_name::Contiguous))
421   }
422 
trait_impl( input: &DeriveInput, _crate_name: &TokenStream, ) -> Result<(TokenStream, TokenStream)>423   fn trait_impl(
424     input: &DeriveInput, _crate_name: &TokenStream,
425   ) -> Result<(TokenStream, TokenStream)> {
426     let repr = get_repr(&input.attrs)?;
427 
428     let integer_ty = if let Some(integer_ty) = repr.repr.as_integer() {
429       integer_ty
430     } else {
431       bail!("Contiguous requires the enum to be #[repr(Int)]");
432     };
433 
434     let variants = get_enum_variants(input)?;
435     if enum_has_fields(variants.clone()) {
436       return Err(Error::new_spanned(
437         &input,
438         "Only fieldless enums are supported",
439       ));
440     }
441 
442     let mut variants_with_discriminator =
443       VariantDiscriminantIterator::new(variants);
444 
445     let (min, max, count) = variants_with_discriminator.try_fold(
446       (i64::max_value(), i64::min_value(), 0),
447       |(min, max, count), res| {
448         let discriminator = res?;
449         Ok::<_, Error>((
450           i64::min(min, discriminator),
451           i64::max(max, discriminator),
452           count + 1,
453         ))
454       },
455     )?;
456 
457     if max - min != count - 1 {
458       bail! {
459         "Contiguous requires the enum discriminants to be contiguous",
460       }
461     }
462 
463     let min_lit = LitInt::new(&format!("{}", min), input.span());
464     let max_lit = LitInt::new(&format!("{}", max), input.span());
465 
466     // `from_integer` and `into_integer` are usually provided by the trait's
467     // default implementation. We override this implementation because it
468     // goes through `transmute_copy`, which can lead to inefficient assembly as seen in https://github.com/Lokathor/bytemuck/issues/175 .
469 
470     Ok((
471       quote!(),
472       quote! {
473           type Int = #integer_ty;
474 
475           #[allow(clippy::missing_docs_in_private_items)]
476           const MIN_VALUE: #integer_ty = #min_lit;
477 
478           #[allow(clippy::missing_docs_in_private_items)]
479           const MAX_VALUE: #integer_ty = #max_lit;
480 
481           #[inline]
482           fn from_integer(value: Self::Int) -> Option<Self> {
483             #[allow(clippy::manual_range_contains)]
484             if Self::MIN_VALUE <= value && value <= Self::MAX_VALUE {
485               Some(unsafe { ::core::mem::transmute(value) })
486             } else {
487               None
488             }
489           }
490 
491           #[inline]
492           fn into_integer(self) -> Self::Int {
493               self as #integer_ty
494           }
495       },
496     ))
497   }
498 }
499 
get_struct_fields(input: &DeriveInput) -> Result<&Fields>500 fn get_struct_fields(input: &DeriveInput) -> Result<&Fields> {
501   if let Data::Struct(DataStruct { fields, .. }) = &input.data {
502     Ok(fields)
503   } else {
504     bail!("deriving this trait is only supported for structs")
505   }
506 }
507 
get_fields(input: &DeriveInput) -> Result<Fields>508 fn get_fields(input: &DeriveInput) -> Result<Fields> {
509   match &input.data {
510     Data::Struct(DataStruct { fields, .. }) => Ok(fields.clone()),
511     Data::Union(DataUnion { fields, .. }) => Ok(Fields::Named(fields.clone())),
512     Data::Enum(_) => bail!("deriving this trait is not supported for enums"),
513   }
514 }
515 
get_enum_variants<'a>( input: &'a DeriveInput, ) -> Result<impl Iterator<Item = &'a Variant> + Clone + 'a>516 fn get_enum_variants<'a>(
517   input: &'a DeriveInput,
518 ) -> Result<impl Iterator<Item = &'a Variant> + Clone + 'a> {
519   if let Data::Enum(DataEnum { variants, .. }) = &input.data {
520     Ok(variants.iter())
521   } else {
522     bail!("deriving this trait is only supported for enums")
523   }
524 }
525 
get_field_types<'a>( fields: &'a Fields, ) -> impl Iterator<Item = &'a Type> + 'a526 fn get_field_types<'a>(
527   fields: &'a Fields,
528 ) -> impl Iterator<Item = &'a Type> + 'a {
529   fields.iter().map(|field| &field.ty)
530 }
531 
generate_checked_bit_pattern_struct( input_ident: &Ident, fields: &Fields, attrs: &[Attribute], crate_name: &TokenStream, ) -> Result<(TokenStream, TokenStream)>532 fn generate_checked_bit_pattern_struct(
533   input_ident: &Ident, fields: &Fields, attrs: &[Attribute],
534   crate_name: &TokenStream,
535 ) -> Result<(TokenStream, TokenStream)> {
536   let bits_ty = Ident::new(&format!("{}Bits", input_ident), input_ident.span());
537 
538   let repr = get_repr(attrs)?;
539 
540   let field_names = fields
541     .iter()
542     .enumerate()
543     .map(|(i, field)| {
544       field.ident.clone().unwrap_or_else(|| {
545         Ident::new(&format!("field{}", i), input_ident.span())
546       })
547     })
548     .collect::<Vec<_>>();
549   let field_tys = fields.iter().map(|field| &field.ty).collect::<Vec<_>>();
550 
551   let field_name = &field_names[..];
552   let field_ty = &field_tys[..];
553 
554   let derive_dbg =
555     quote!(#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]);
556 
557   Ok((
558     quote! {
559         #[doc = #GENERATED_TYPE_DOCUMENTATION]
560         #repr
561         #[derive(Clone, Copy, #crate_name::AnyBitPattern)]
562         #derive_dbg
563         #[allow(missing_docs)]
564         pub struct #bits_ty {
565             #(#field_name: <#field_ty as #crate_name::CheckedBitPattern>::Bits,)*
566         }
567     },
568     quote! {
569         type Bits = #bits_ty;
570 
571         #[inline]
572         #[allow(clippy::double_comparisons, unused)]
573         fn is_valid_bit_pattern(bits: &#bits_ty) -> bool {
574             #(<#field_ty as #crate_name::CheckedBitPattern>::is_valid_bit_pattern(&{ bits.#field_name }) && )* true
575         }
576     },
577   ))
578 }
579 
generate_checked_bit_pattern_enum( input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>, crate_name: &TokenStream, ) -> Result<(TokenStream, TokenStream)>580 fn generate_checked_bit_pattern_enum(
581   input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>,
582   crate_name: &TokenStream,
583 ) -> Result<(TokenStream, TokenStream)> {
584   if enum_has_fields(variants.iter()) {
585     generate_checked_bit_pattern_enum_with_fields(input, variants, crate_name)
586   } else {
587     generate_checked_bit_pattern_enum_without_fields(input, variants)
588   }
589 }
590 
generate_checked_bit_pattern_enum_without_fields( input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>, ) -> Result<(TokenStream, TokenStream)>591 fn generate_checked_bit_pattern_enum_without_fields(
592   input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>,
593 ) -> Result<(TokenStream, TokenStream)> {
594   let span = input.span();
595   let mut variants_with_discriminant =
596     VariantDiscriminantIterator::new(variants.iter());
597 
598   let (min, max, count) = variants_with_discriminant.try_fold(
599     (i64::max_value(), i64::min_value(), 0),
600     |(min, max, count), res| {
601       let discriminant = res?;
602       Ok::<_, Error>((
603         i64::min(min, discriminant),
604         i64::max(max, discriminant),
605         count + 1,
606       ))
607     },
608   )?;
609 
610   let check = if count == 0 {
611     quote_spanned!(span => false)
612   } else if max - min == count - 1 {
613     // contiguous range
614     let min_lit = LitInt::new(&format!("{}", min), span);
615     let max_lit = LitInt::new(&format!("{}", max), span);
616 
617     quote!(*bits >= #min_lit && *bits <= #max_lit)
618   } else {
619     // not contiguous range, check for each
620     let variant_lits = VariantDiscriminantIterator::new(variants.iter())
621       .map(|res| {
622         let variant = res?;
623         Ok(LitInt::new(&format!("{}", variant), span))
624       })
625       .collect::<Result<Vec<_>>>()?;
626 
627     // count is at least 1
628     let first = &variant_lits[0];
629     let rest = &variant_lits[1..];
630 
631     quote!(matches!(*bits, #first #(| #rest )*))
632   };
633 
634   let repr = get_repr(&input.attrs)?;
635   let integer = repr.repr.as_integer().unwrap(); // should be checked in attr check already
636   Ok((
637     quote!(),
638     quote! {
639         type Bits = #integer;
640 
641         #[inline]
642         #[allow(clippy::double_comparisons)]
643         fn is_valid_bit_pattern(bits: &Self::Bits) -> bool {
644             #check
645         }
646     },
647   ))
648 }
649 
generate_checked_bit_pattern_enum_with_fields( input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>, crate_name: &TokenStream, ) -> Result<(TokenStream, TokenStream)>650 fn generate_checked_bit_pattern_enum_with_fields(
651   input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>,
652   crate_name: &TokenStream,
653 ) -> Result<(TokenStream, TokenStream)> {
654   let representation = get_repr(&input.attrs)?;
655   let vis = &input.vis;
656 
657   let derive_dbg =
658     quote!(#[cfg_attr(not(target_arch = "spirv"), derive(Debug))]);
659 
660   match representation.repr {
661     Repr::Rust => unreachable!(),
662     repr @ (Repr::C | Repr::CWithDiscriminant(_)) => {
663       let integer = match repr {
664         Repr::C => quote!(::core::ffi::c_int),
665         Repr::CWithDiscriminant(integer) => quote!(#integer),
666         _ => unreachable!(),
667       };
668       let input_ident = &input.ident;
669 
670       let bits_repr = Representation { repr: Repr::C, ..representation };
671 
672       // the enum manually re-configured as the actual tagged union it
673       // represents, thus circumventing the requirements rust imposes on
674       // the tag even when using #[repr(C)] enum layout
675       // see: https://doc.rust-lang.org/reference/type-layout.html#reprc-enums-with-fields
676       let bits_ty_ident =
677         Ident::new(&format!("{input_ident}Bits"), input.span());
678 
679       // the variants union part of the tagged union. These get put into a union
680       // which gets the AnyBitPattern derive applied to it, thus checking
681       // that the fields of the union obey the requriements of AnyBitPattern.
682       // The types that actually go in the union are one more level of
683       // indirection deep: we generate new structs for each variant
684       // (`variant_struct_definitions`) which themselves have the
685       // `CheckedBitPattern` derive applied, thus generating
686       // `{variant_struct_ident}Bits` structs, which are the ones that go
687       // into this union.
688       let variants_union_ident =
689         Ident::new(&format!("{}Variants", input.ident), input.span());
690 
691       let variant_struct_idents = variants.iter().map(|v| {
692         Ident::new(&format!("{input_ident}Variant{}", v.ident), v.span())
693       });
694 
695       let variant_struct_definitions =
696         variant_struct_idents.clone().zip(variants.iter()).map(|(variant_struct_ident, v)| {
697           let fields = v.fields.iter().map(|v| &v.ty);
698 
699           quote! {
700             #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::CheckedBitPattern)]
701             #[repr(C)]
702             #vis struct #variant_struct_ident(#(#fields),*);
703           }
704         });
705 
706       let union_fields = variant_struct_idents
707         .clone()
708         .zip(variants.iter())
709         .map(|(variant_struct_ident, v)| {
710           let variant_struct_bits_ident =
711             Ident::new(&format!("{variant_struct_ident}Bits"), input.span());
712           let field_ident = &v.ident;
713           quote! {
714             #field_ident: #variant_struct_bits_ident
715           }
716         });
717 
718       let variant_checks = variant_struct_idents
719         .clone()
720         .zip(VariantDiscriminantIterator::new(variants.iter()))
721         .zip(variants.iter())
722         .map(|((variant_struct_ident, discriminant), v)| -> Result<_> {
723           let discriminant = discriminant?;
724           let discriminant = LitInt::new(&discriminant.to_string(), v.span());
725           let ident = &v.ident;
726           Ok(quote! {
727             #discriminant => {
728               let payload = unsafe { &bits.payload.#ident };
729               <#variant_struct_ident as #crate_name::CheckedBitPattern>::is_valid_bit_pattern(payload)
730             }
731           })
732         })
733         .collect::<Result<Vec<_>>>()?;
734 
735       Ok((
736         quote! {
737           #[doc = #GENERATED_TYPE_DOCUMENTATION]
738           #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::AnyBitPattern)]
739           #derive_dbg
740           #bits_repr
741           #vis struct #bits_ty_ident {
742             tag: #integer,
743             payload: #variants_union_ident,
744           }
745 
746           #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::AnyBitPattern)]
747           #[repr(C)]
748           #[allow(non_snake_case)]
749           #vis union #variants_union_ident {
750             #(#union_fields,)*
751           }
752 
753           #[cfg(not(target_arch = "spirv"))]
754           impl ::core::fmt::Debug for #variants_union_ident {
755             fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
756               let mut debug_struct = ::core::fmt::Formatter::debug_struct(f, ::core::stringify!(#variants_union_ident));
757               ::core::fmt::DebugStruct::finish_non_exhaustive(&mut debug_struct)
758             }
759           }
760 
761           #(#variant_struct_definitions)*
762         },
763         quote! {
764           type Bits = #bits_ty_ident;
765 
766           #[inline]
767           #[allow(clippy::double_comparisons)]
768           fn is_valid_bit_pattern(bits: &Self::Bits) -> bool {
769             match bits.tag {
770               #(#variant_checks)*
771               _ => false,
772             }
773           }
774         },
775       ))
776     }
777     Repr::Transparent => {
778       if variants.len() != 1 {
779         bail!("enums with more than one variant cannot be transparent")
780       }
781 
782       let variant = &variants[0];
783 
784       let bits_ty = Ident::new(&format!("{}Bits", input.ident), input.span());
785       let fields = variant.fields.iter().map(|v| &v.ty);
786 
787       Ok((
788         quote! {
789           #[doc = #GENERATED_TYPE_DOCUMENTATION]
790           #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::CheckedBitPattern)]
791           #[repr(C)]
792           #vis struct #bits_ty(#(#fields),*);
793         },
794         quote! {
795           type Bits = <#bits_ty as #crate_name::CheckedBitPattern>::Bits;
796 
797           #[inline]
798           #[allow(clippy::double_comparisons)]
799           fn is_valid_bit_pattern(bits: &Self::Bits) -> bool {
800             <#bits_ty as #crate_name::CheckedBitPattern>::is_valid_bit_pattern(bits)
801           }
802         },
803       ))
804     }
805     Repr::Integer(integer) => {
806       let bits_repr = Representation { repr: Repr::C, ..representation };
807       let input_ident = &input.ident;
808 
809       // the enum manually re-configured as the union it represents. such a
810       // union is the union of variants as a repr(c) struct with the
811       // discriminator type inserted at the beginning. in our case we
812       // union the `Bits` representation of each variant rather than the variant
813       // itself, which we generate via a nested `CheckedBitPattern` derive
814       // on the `variant_struct_definitions` generated below.
815       //
816       // see: https://doc.rust-lang.org/reference/type-layout.html#primitive-representation-of-enums-with-fields
817       let bits_ty_ident =
818         Ident::new(&format!("{input_ident}Bits"), input.span());
819 
820       let variant_struct_idents = variants.iter().map(|v| {
821         Ident::new(&format!("{input_ident}Variant{}", v.ident), v.span())
822       });
823 
824       let variant_struct_definitions =
825         variant_struct_idents.clone().zip(variants.iter()).map(|(variant_struct_ident, v)| {
826           let fields = v.fields.iter().map(|v| &v.ty);
827 
828           // adding the discriminant repr integer as first field, as described above
829           quote! {
830             #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::CheckedBitPattern)]
831             #[repr(C)]
832             #vis struct #variant_struct_ident(#integer, #(#fields),*);
833           }
834         });
835 
836       let union_fields = variant_struct_idents
837         .clone()
838         .zip(variants.iter())
839         .map(|(variant_struct_ident, v)| {
840           let variant_struct_bits_ident =
841             Ident::new(&format!("{variant_struct_ident}Bits"), input.span());
842           let field_ident = &v.ident;
843           quote! {
844             #field_ident: #variant_struct_bits_ident
845           }
846         });
847 
848       let variant_checks = variant_struct_idents
849         .clone()
850         .zip(VariantDiscriminantIterator::new(variants.iter()))
851         .zip(variants.iter())
852         .map(|((variant_struct_ident, discriminant), v)| -> Result<_> {
853           let discriminant = discriminant?;
854           let discriminant = LitInt::new(&discriminant.to_string(), v.span());
855           let ident = &v.ident;
856           Ok(quote! {
857             #discriminant => {
858               let payload = unsafe { &bits.#ident };
859               <#variant_struct_ident as #crate_name::CheckedBitPattern>::is_valid_bit_pattern(payload)
860             }
861           })
862         })
863         .collect::<Result<Vec<_>>>()?;
864 
865       Ok((
866         quote! {
867           #[doc = #GENERATED_TYPE_DOCUMENTATION]
868           #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::AnyBitPattern)]
869           #bits_repr
870           #[allow(non_snake_case)]
871           #vis union #bits_ty_ident {
872             __tag: #integer,
873             #(#union_fields,)*
874           }
875 
876           #[cfg(not(target_arch = "spirv"))]
877           impl ::core::fmt::Debug for #bits_ty_ident {
878             fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
879               let mut debug_struct = ::core::fmt::Formatter::debug_struct(f, ::core::stringify!(#bits_ty_ident));
880               ::core::fmt::DebugStruct::field(&mut debug_struct, "tag", unsafe { &self.__tag });
881               ::core::fmt::DebugStruct::finish_non_exhaustive(&mut debug_struct)
882             }
883           }
884 
885           #(#variant_struct_definitions)*
886         },
887         quote! {
888           type Bits = #bits_ty_ident;
889 
890           #[inline]
891           #[allow(clippy::double_comparisons)]
892           fn is_valid_bit_pattern(bits: &Self::Bits) -> bool {
893             match unsafe { bits.__tag } {
894               #(#variant_checks)*
895               _ => false,
896             }
897           }
898         },
899       ))
900     }
901   }
902 }
903 
904 /// Check that a struct has no padding by asserting that the size of the struct
905 /// is equal to the sum of the size of it's fields
generate_assert_no_padding(input: &DeriveInput) -> Result<TokenStream>906 fn generate_assert_no_padding(input: &DeriveInput) -> Result<TokenStream> {
907   let struct_type = &input.ident;
908   let span = input.ident.span();
909   let fields = get_fields(input)?;
910 
911   let mut field_types = get_field_types(&fields);
912   let size_sum = if let Some(first) = field_types.next() {
913     let size_first = quote_spanned!(span => ::core::mem::size_of::<#first>());
914     let size_rest =
915       quote_spanned!(span => #( + ::core::mem::size_of::<#field_types>() )*);
916 
917     quote_spanned!(span => #size_first #size_rest)
918   } else {
919     quote_spanned!(span => 0)
920   };
921 
922   Ok(quote_spanned! {span => const _: fn() = || {
923     #[doc(hidden)]
924     struct TypeWithoutPadding([u8; #size_sum]);
925     let _ = ::core::mem::transmute::<#struct_type, TypeWithoutPadding>;
926   };})
927 }
928 
929 /// Check that all fields implement a given trait
generate_fields_are_trait( input: &DeriveInput, trait_: syn::Path, ) -> Result<TokenStream>930 fn generate_fields_are_trait(
931   input: &DeriveInput, trait_: syn::Path,
932 ) -> Result<TokenStream> {
933   let (impl_generics, _ty_generics, where_clause) =
934     input.generics.split_for_impl();
935   let fields = get_fields(input)?;
936   let span = input.span();
937   let field_types = get_field_types(&fields);
938   Ok(quote_spanned! {span => #(const _: fn() = || {
939       #[allow(clippy::missing_const_for_fn)]
940       #[doc(hidden)]
941       fn check #impl_generics () #where_clause {
942         fn assert_impl<T: #trait_>() {}
943         assert_impl::<#field_types>();
944       }
945     };)*
946   })
947 }
948 
get_ident_from_stream(tokens: TokenStream) -> Option<Ident>949 fn get_ident_from_stream(tokens: TokenStream) -> Option<Ident> {
950   match tokens.into_iter().next() {
951     Some(TokenTree::Group(group)) => get_ident_from_stream(group.stream()),
952     Some(TokenTree::Ident(ident)) => Some(ident),
953     _ => None,
954   }
955 }
956 
957 /// get a simple #[foo(bar)] attribute, returning "bar"
get_simple_attr(attributes: &[Attribute], attr_name: &str) -> Option<Ident>958 fn get_simple_attr(attributes: &[Attribute], attr_name: &str) -> Option<Ident> {
959   for attr in attributes {
960     if let (AttrStyle::Outer, Meta::List(list)) = (&attr.style, &attr.meta) {
961       if list.path.is_ident(attr_name) {
962         if let Some(ident) = get_ident_from_stream(list.tokens.clone()) {
963           return Some(ident);
964         }
965       }
966     }
967   }
968 
969   None
970 }
971 
get_repr(attributes: &[Attribute]) -> Result<Representation>972 fn get_repr(attributes: &[Attribute]) -> Result<Representation> {
973   attributes
974     .iter()
975     .filter_map(|attr| {
976       if attr.path().is_ident("repr") {
977         Some(attr.parse_args::<Representation>())
978       } else {
979         None
980       }
981     })
982     .try_fold(Representation::default(), |a, b| {
983       let b = b?;
984       Ok(Representation {
985         repr: match (a.repr, b.repr) {
986           (a, Repr::Rust) => a,
987           (Repr::Rust, b) => b,
988           _ => bail!("conflicting representation hints"),
989         },
990         packed: match (a.packed, b.packed) {
991           (a, None) => a,
992           (None, b) => b,
993           _ => bail!("conflicting representation hints"),
994         },
995         align: match (a.align, b.align) {
996           (Some(a), Some(b)) => Some(cmp::max(a, b)),
997           (a, None) => a,
998           (None, b) => b,
999         },
1000       })
1001     })
1002 }
1003 
1004 mk_repr! {
1005   U8 => u8,
1006   I8 => i8,
1007   U16 => u16,
1008   I16 => i16,
1009   U32 => u32,
1010   I32 => i32,
1011   U64 => u64,
1012   I64 => i64,
1013   I128 => i128,
1014   U128 => u128,
1015   Usize => usize,
1016   Isize => isize,
1017 }
1018 // where
1019 macro_rules! mk_repr {(
1020   $(
1021     $Xn:ident => $xn:ident
1022   ),* $(,)?
1023 ) => (
1024   #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1025   enum IntegerRepr {
1026     $($Xn),*
1027   }
1028 
1029   impl<'a> TryFrom<&'a str> for IntegerRepr {
1030     type Error = &'a str;
1031 
1032     fn try_from(value: &'a str) -> std::result::Result<Self, &'a str> {
1033       match value {
1034         $(
1035           stringify!($xn) => Ok(Self::$Xn),
1036         )*
1037         _ => Err(value),
1038       }
1039     }
1040   }
1041 
1042   impl ToTokens for IntegerRepr {
1043     fn to_tokens(&self, tokens: &mut TokenStream) {
1044       match self {
1045         $(
1046           Self::$Xn => tokens.extend(quote!($xn)),
1047         )*
1048       }
1049     }
1050   }
1051 )}
1052 use mk_repr;
1053 
1054 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1055 enum Repr {
1056   Rust,
1057   C,
1058   Transparent,
1059   Integer(IntegerRepr),
1060   CWithDiscriminant(IntegerRepr),
1061 }
1062 
1063 impl Repr {
is_integer(&self) -> bool1064   fn is_integer(&self) -> bool {
1065     matches!(self, Self::Integer(..))
1066   }
1067 
as_integer(&self) -> Option<IntegerRepr>1068   fn as_integer(&self) -> Option<IntegerRepr> {
1069     if let Self::Integer(v) = self {
1070       Some(*v)
1071     } else {
1072       None
1073     }
1074   }
1075 }
1076 
1077 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1078 struct Representation {
1079   packed: Option<u32>,
1080   align: Option<u32>,
1081   repr: Repr,
1082 }
1083 
1084 impl Default for Representation {
default() -> Self1085   fn default() -> Self {
1086     Self { packed: None, align: None, repr: Repr::Rust }
1087   }
1088 }
1089 
1090 impl Parse for Representation {
parse(input: ParseStream<'_>) -> Result<Representation>1091   fn parse(input: ParseStream<'_>) -> Result<Representation> {
1092     let mut ret = Representation::default();
1093     while !input.is_empty() {
1094       let keyword = input.parse::<Ident>()?;
1095       // preëmptively call `.to_string()` *once* (rather than on `is_ident()`)
1096       let keyword_str = keyword.to_string();
1097       let new_repr = match keyword_str.as_str() {
1098         "C" => Repr::C,
1099         "transparent" => Repr::Transparent,
1100         "packed" => {
1101           ret.packed = Some(if input.peek(token::Paren) {
1102             let contents;
1103             parenthesized!(contents in input);
1104             LitInt::base10_parse::<u32>(&contents.parse()?)?
1105           } else {
1106             1
1107           });
1108           let _: Option<Token![,]> = input.parse()?;
1109           continue;
1110         }
1111         "align" => {
1112           let contents;
1113           parenthesized!(contents in input);
1114           let new_align = LitInt::base10_parse::<u32>(&contents.parse()?)?;
1115           ret.align = Some(
1116             ret
1117               .align
1118               .map_or(new_align, |old_align| cmp::max(old_align, new_align)),
1119           );
1120           let _: Option<Token![,]> = input.parse()?;
1121           continue;
1122         }
1123         ident => {
1124           let primitive = IntegerRepr::try_from(ident)
1125             .map_err(|_| input.error("unrecognized representation hint"))?;
1126           Repr::Integer(primitive)
1127         }
1128       };
1129       ret.repr = match (ret.repr, new_repr) {
1130         (Repr::Rust, new_repr) => {
1131           // This is the first explicit repr.
1132           new_repr
1133         }
1134         (Repr::C, Repr::Integer(integer))
1135         | (Repr::Integer(integer), Repr::C) => {
1136           // Both the C repr and an integer repr have been specified
1137           // -> merge into a C wit discriminant.
1138           Repr::CWithDiscriminant(integer)
1139         }
1140         (_, _) => {
1141           return Err(input.error("duplicate representation hint"));
1142         }
1143       };
1144       let _: Option<Token![,]> = input.parse()?;
1145     }
1146     Ok(ret)
1147   }
1148 }
1149 
1150 impl ToTokens for Representation {
to_tokens(&self, tokens: &mut TokenStream)1151   fn to_tokens(&self, tokens: &mut TokenStream) {
1152     let mut meta = Punctuated::<_, Token![,]>::new();
1153 
1154     match self.repr {
1155       Repr::Rust => {}
1156       Repr::C => meta.push(quote!(C)),
1157       Repr::Transparent => meta.push(quote!(transparent)),
1158       Repr::Integer(primitive) => meta.push(quote!(#primitive)),
1159       Repr::CWithDiscriminant(primitive) => {
1160         meta.push(quote!(C));
1161         meta.push(quote!(#primitive));
1162       }
1163     }
1164 
1165     if let Some(packed) = self.packed.as_ref() {
1166       let lit = LitInt::new(&packed.to_string(), Span::call_site());
1167       meta.push(quote!(packed(#lit)));
1168     }
1169 
1170     if let Some(align) = self.align.as_ref() {
1171       let lit = LitInt::new(&align.to_string(), Span::call_site());
1172       meta.push(quote!(align(#lit)));
1173     }
1174 
1175     tokens.extend(quote!(
1176       #[repr(#meta)]
1177     ));
1178   }
1179 }
1180 
enum_has_fields<'a>( mut variants: impl Iterator<Item = &'a Variant>, ) -> bool1181 fn enum_has_fields<'a>(
1182   mut variants: impl Iterator<Item = &'a Variant>,
1183 ) -> bool {
1184   variants.any(|v| matches!(v.fields, Fields::Named(_) | Fields::Unnamed(_)))
1185 }
1186 
1187 struct VariantDiscriminantIterator<'a, I: Iterator<Item = &'a Variant> + 'a> {
1188   inner: I,
1189   last_value: i64,
1190 }
1191 
1192 impl<'a, I: Iterator<Item = &'a Variant> + 'a>
1193   VariantDiscriminantIterator<'a, I>
1194 {
new(inner: I) -> Self1195   fn new(inner: I) -> Self {
1196     VariantDiscriminantIterator { inner, last_value: -1 }
1197   }
1198 }
1199 
1200 impl<'a, I: Iterator<Item = &'a Variant> + 'a> Iterator
1201   for VariantDiscriminantIterator<'a, I>
1202 {
1203   type Item = Result<i64>;
1204 
next(&mut self) -> Option<Self::Item>1205   fn next(&mut self) -> Option<Self::Item> {
1206     let variant = self.inner.next()?;
1207 
1208     if let Some((_, discriminant)) = &variant.discriminant {
1209       let discriminant_value = match parse_int_expr(discriminant) {
1210         Ok(value) => value,
1211         Err(e) => return Some(Err(e)),
1212       };
1213       self.last_value = discriminant_value;
1214     } else {
1215       self.last_value += 1;
1216     }
1217 
1218     Some(Ok(self.last_value))
1219   }
1220 }
1221 
parse_int_expr(expr: &Expr) -> Result<i64>1222 fn parse_int_expr(expr: &Expr) -> Result<i64> {
1223   match expr {
1224     Expr::Unary(ExprUnary { op: UnOp::Neg(_), expr, .. }) => {
1225       parse_int_expr(expr).map(|int| -int)
1226     }
1227     Expr::Lit(ExprLit { lit: Lit::Int(int), .. }) => int.base10_parse(),
1228     Expr::Lit(ExprLit { lit: Lit::Byte(byte), .. }) => Ok(byte.value().into()),
1229     _ => bail!("Not an integer expression"),
1230   }
1231 }
1232 
1233 #[cfg(test)]
1234 mod tests {
1235   use syn::parse_quote;
1236 
1237   use super::{get_repr, IntegerRepr, Repr, Representation};
1238 
1239   #[test]
parse_basic_repr()1240   fn parse_basic_repr() {
1241     let attr = parse_quote!(#[repr(C)]);
1242     let repr = get_repr(&[attr]).unwrap();
1243     assert_eq!(repr, Representation { repr: Repr::C, ..Default::default() });
1244 
1245     let attr = parse_quote!(#[repr(transparent)]);
1246     let repr = get_repr(&[attr]).unwrap();
1247     assert_eq!(
1248       repr,
1249       Representation { repr: Repr::Transparent, ..Default::default() }
1250     );
1251 
1252     let attr = parse_quote!(#[repr(u8)]);
1253     let repr = get_repr(&[attr]).unwrap();
1254     assert_eq!(
1255       repr,
1256       Representation {
1257         repr: Repr::Integer(IntegerRepr::U8),
1258         ..Default::default()
1259       }
1260     );
1261 
1262     let attr = parse_quote!(#[repr(packed)]);
1263     let repr = get_repr(&[attr]).unwrap();
1264     assert_eq!(repr, Representation { packed: Some(1), ..Default::default() });
1265 
1266     let attr = parse_quote!(#[repr(packed(1))]);
1267     let repr = get_repr(&[attr]).unwrap();
1268     assert_eq!(repr, Representation { packed: Some(1), ..Default::default() });
1269 
1270     let attr = parse_quote!(#[repr(packed(2))]);
1271     let repr = get_repr(&[attr]).unwrap();
1272     assert_eq!(repr, Representation { packed: Some(2), ..Default::default() });
1273 
1274     let attr = parse_quote!(#[repr(align(2))]);
1275     let repr = get_repr(&[attr]).unwrap();
1276     assert_eq!(repr, Representation { align: Some(2), ..Default::default() });
1277   }
1278 
1279   #[test]
parse_advanced_repr()1280   fn parse_advanced_repr() {
1281     let attr = parse_quote!(#[repr(align(4), align(2))]);
1282     let repr = get_repr(&[attr]).unwrap();
1283     assert_eq!(repr, Representation { align: Some(4), ..Default::default() });
1284 
1285     let attr1 = parse_quote!(#[repr(align(1))]);
1286     let attr2 = parse_quote!(#[repr(align(4))]);
1287     let attr3 = parse_quote!(#[repr(align(2))]);
1288     let repr = get_repr(&[attr1, attr2, attr3]).unwrap();
1289     assert_eq!(repr, Representation { align: Some(4), ..Default::default() });
1290 
1291     let attr = parse_quote!(#[repr(C, u8)]);
1292     let repr = get_repr(&[attr]).unwrap();
1293     assert_eq!(
1294       repr,
1295       Representation {
1296         repr: Repr::CWithDiscriminant(IntegerRepr::U8),
1297         ..Default::default()
1298       }
1299     );
1300 
1301     let attr = parse_quote!(#[repr(u8, C)]);
1302     let repr = get_repr(&[attr]).unwrap();
1303     assert_eq!(
1304       repr,
1305       Representation {
1306         repr: Repr::CWithDiscriminant(IntegerRepr::U8),
1307         ..Default::default()
1308       }
1309     );
1310   }
1311 }
1312 
bytemuck_crate_name(input: &DeriveInput) -> TokenStream1313 pub fn bytemuck_crate_name(input: &DeriveInput) -> TokenStream {
1314   const ATTR_NAME: &'static str = "crate";
1315 
1316   let mut crate_name = quote!(::bytemuck);
1317   for attr in &input.attrs {
1318     if !attr.path().is_ident("bytemuck") {
1319       continue;
1320     }
1321 
1322     attr.parse_nested_meta(|meta| {
1323       if meta.path.is_ident(ATTR_NAME) {
1324         let expr: syn::Expr = meta.value()?.parse()?;
1325         let mut value = &expr;
1326         while let syn::Expr::Group(e) = value {
1327           value = &e.expr;
1328         }
1329         if let syn::Expr::Lit(syn::ExprLit {
1330           lit: syn::Lit::Str(lit), ..
1331         }) = value
1332         {
1333           let suffix = lit.suffix();
1334           if !suffix.is_empty() {
1335             bail!(format!("Unexpected suffix `{}` on string literal", suffix))
1336           }
1337           let path: syn::Path = match lit.parse() {
1338             Ok(path) => path,
1339             Err(_) => {
1340               bail!(format!("Failed to parse path: {:?}", lit.value()))
1341             }
1342           };
1343           crate_name = path.into_token_stream();
1344         } else {
1345           bail!(
1346             "Expected bytemuck `crate` attribute to be a string: `crate = \"...\"`",
1347           )
1348         }
1349       }
1350       Ok(())
1351     }).unwrap();
1352   }
1353 
1354   return crate_name;
1355 }
1356 
1357 const GENERATED_TYPE_DOCUMENTATION: &str =
1358   " `bytemuck`-generated type for internal purposes only.";
1359