1use proc_macro::TokenStream;
6use quote::quote;
7use syn::{parse_macro_input, AttrStyle, Attribute, DeriveInput, Path};
8
9macro_rules! repr_derive {
10 ($tr:ident : $fn:ident($inner:expr) ) => {
11 #[proc_macro_derive($tr)]
12 pub fn $fn(input: TokenStream) -> TokenStream {
13 let input = parse_macro_input!(input as DeriveInput);
14
15 let ident = input.ident;
16
17 if has_repr(&input.attrs, $inner) {
18 quote!(
19 unsafe impl $tr for #ident {}
20 ).into()
21 } else {
22 panic!("Can't derive {} on a struct without #[repr({})]", stringify!($tr), $inner);
23 }
24 }
25 }
26}
27
28repr_derive!(Packed: repr_packed("packed"));
29repr_derive!(Transparent: repr_transparent("transparent"));
30repr_derive!(C: repr_c("C"));
31
32fn has_repr(attrs: &[Attribute], repr: &str) -> bool {
33 for attr in attrs {
34 if !matches!(attr.style, AttrStyle::Outer) {
36 continue;
37 }
38
39 if let Path {
41 leading_colon: None,
42 ref segments,
43 } = attr.path
44 {
45 if segments.len() != 1 {
47 continue;
48 }
49
50 let seg = segments.first().unwrap();
51
52 if !seg.arguments.is_empty() {
54 continue;
55 }
56
57 if seg.ident.to_string() != "repr" {
59 continue;
60 }
61 } else {
62 continue;
64 }
65
66 if format!("{}", attr.tokens) != format!("({})", repr) {
68 continue;
69 }
70
71 return true;
72 }
73
74 false
75}