1 use attr;
2 use proc_macro2;
3 use syn;
4 use syn::spanned::Spanned as SynSpanned;
5 
6 #[derive(Debug)]
7 pub struct Input<'a> {
8     pub attrs: attr::Input,
9     pub body: Body<'a>,
10     pub generics: &'a syn::Generics,
11     pub ident: syn::Ident,
12     pub span: proc_macro2::Span,
13 }
14 
15 #[derive(Debug)]
16 pub enum Body<'a> {
17     Enum(Vec<Variant<'a>>),
18     Struct(Style, Vec<Field<'a>>),
19 }
20 
21 #[derive(Debug)]
22 pub struct Variant<'a> {
23     pub attrs: attr::Input,
24     pub fields: Vec<Field<'a>>,
25     pub ident: syn::Ident,
26     pub style: Style,
27 }
28 
29 #[derive(Debug)]
30 pub struct Field<'a> {
31     pub attrs: attr::Field,
32     pub ident: Option<syn::Ident>,
33     pub ty: &'a syn::Type,
34     pub span: proc_macro2::Span,
35 }
36 
37 #[derive(Clone, Copy, Debug)]
38 pub enum Style {
39     Struct,
40     Tuple,
41     Unit,
42 }
43 
44 impl<'a> Input<'a> {
from_ast( item: &'a syn::DeriveInput, errors: &mut proc_macro2::TokenStream, ) -> Result<Input<'a>, ()>45     pub fn from_ast(
46         item: &'a syn::DeriveInput,
47         errors: &mut proc_macro2::TokenStream,
48     ) -> Result<Input<'a>, ()> {
49         let attrs = attr::Input::from_ast(&item.attrs, errors)?;
50 
51         let body = match item.data {
52             syn::Data::Enum(syn::DataEnum { ref variants, .. }) => {
53                 Body::Enum(enum_from_ast(variants, errors)?)
54             }
55             syn::Data::Struct(syn::DataStruct { ref fields, .. }) => {
56                 let (style, fields) = struct_from_ast(fields, errors)?;
57                 Body::Struct(style, fields)
58             }
59             syn::Data::Union(..) => {
60                 errors.extend(
61                     syn::Error::new_spanned(item, "derivative does not support unions")
62                         .to_compile_error(),
63                 );
64                 return Err(());
65             }
66         };
67 
68         Ok(Input {
69             attrs,
70             body,
71             generics: &item.generics,
72             ident: item.ident.clone(),
73             span: item.span(),
74         })
75     }
76 
77     /// Checks whether this type is an enum with only unit variants.
is_trivial_enum(&self) -> bool78     pub fn is_trivial_enum(&self) -> bool {
79         match &self.body {
80             Body::Enum(e) => e.iter().all(|v| v.is_unit()),
81             Body::Struct(..) => false,
82         }
83     }
84 }
85 
86 impl<'a> Body<'a> {
all_fields(&self) -> Vec<&Field>87     pub fn all_fields(&self) -> Vec<&Field> {
88         match *self {
89             Body::Enum(ref variants) => variants
90                 .iter()
91                 .flat_map(|variant| variant.fields.iter())
92                 .collect(),
93             Body::Struct(_, ref fields) => fields.iter().collect(),
94         }
95     }
96 
is_empty(&self) -> bool97     pub fn is_empty(&self) -> bool {
98         match *self {
99             Body::Enum(ref variants) => variants.is_empty(),
100             Body::Struct(_, ref fields) => fields.is_empty(),
101         }
102     }
103 }
104 
105 impl<'a> Variant<'a> {
106     /// Checks whether this variant is a unit variant.
is_unit(&self) -> bool107     pub fn is_unit(&self) -> bool {
108         self.fields.is_empty()
109     }
110 }
111 
enum_from_ast<'a>( variants: &'a syn::punctuated::Punctuated<syn::Variant, syn::token::Comma>, errors: &mut proc_macro2::TokenStream, ) -> Result<Vec<Variant<'a>>, ()>112 fn enum_from_ast<'a>(
113     variants: &'a syn::punctuated::Punctuated<syn::Variant, syn::token::Comma>,
114     errors: &mut proc_macro2::TokenStream,
115 ) -> Result<Vec<Variant<'a>>, ()> {
116     variants
117         .iter()
118         .map(|variant| {
119             let (style, fields) = struct_from_ast(&variant.fields, errors)?;
120             Ok(Variant {
121                 attrs: attr::Input::from_ast(&variant.attrs, errors)?,
122                 fields,
123                 ident: variant.ident.clone(),
124                 style,
125             })
126         })
127         .collect()
128 }
129 
struct_from_ast<'a>( fields: &'a syn::Fields, errors: &mut proc_macro2::TokenStream, ) -> Result<(Style, Vec<Field<'a>>), ()>130 fn struct_from_ast<'a>(
131     fields: &'a syn::Fields,
132     errors: &mut proc_macro2::TokenStream,
133 ) -> Result<(Style, Vec<Field<'a>>), ()> {
134     match *fields {
135         syn::Fields::Named(ref fields) => {
136             Ok((Style::Struct, fields_from_ast(&fields.named, errors)?))
137         }
138         syn::Fields::Unnamed(ref fields) => {
139             Ok((Style::Tuple, fields_from_ast(&fields.unnamed, errors)?))
140         }
141         syn::Fields::Unit => Ok((Style::Unit, Vec::new())),
142     }
143 }
144 
fields_from_ast<'a>( fields: &'a syn::punctuated::Punctuated<syn::Field, syn::token::Comma>, errors: &mut proc_macro2::TokenStream, ) -> Result<Vec<Field<'a>>, ()>145 fn fields_from_ast<'a>(
146     fields: &'a syn::punctuated::Punctuated<syn::Field, syn::token::Comma>,
147     errors: &mut proc_macro2::TokenStream,
148 ) -> Result<Vec<Field<'a>>, ()> {
149     fields
150         .iter()
151         .map(|field| {
152             Ok(Field {
153                 attrs: attr::Field::from_ast(field, errors)?,
154                 ident: field.ident.clone(),
155                 ty: &field.ty,
156                 span: field.span(),
157             })
158         })
159         .collect()
160 }
161