1use attr;
2use proc_macro2;
3use syn;
4use syn::spanned::Spanned as SynSpanned;
5
6#[derive(Debug)]
7pub 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)]
16pub enum Body<'a> {
17 Enum(Vec<Variant<'a>>),
18 Struct(Style, Vec<Field<'a>>),
19}
20
21#[derive(Debug)]
22pub 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)]
30pub 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)]
38pub enum Style {
39 Struct,
40 Tuple,
41 Unit,
42}
43
44impl<'a> 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.
78 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
86impl<'a> Body<'a> {
87 pub fn all_fields(&self) -> Vec<&Field> {
88 match *self {
89 Body::Enum(ref variants: &Vec>) => variantsimpl Iterator>
90 .iter()
91 .flat_map(|variant: &Variant<'_>| variant.fields.iter())
92 .collect(),
93 Body::Struct(_, ref fields: &Vec>) => fields.iter().collect(),
94 }
95 }
96
97 pub fn is_empty(&self) -> bool {
98 match *self {
99 Body::Enum(ref variants: &Vec>) => variants.is_empty(),
100 Body::Struct(_, ref fields: &Vec>) => fields.is_empty(),
101 }
102 }
103}
104
105impl<'a> Variant<'a> {
106 /// Checks whether this variant is a unit variant.
107 pub fn is_unit(&self) -> bool {
108 self.fields.is_empty()
109 }
110}
111
112fn 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 variantsimpl Iterator>
117 .iter()
118 .map(|variant: &Variant| {
119 let (style: Style, fields: Vec>) = 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
130fn 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: &FieldsNamed) => {
136 Ok((Style::Struct, fields_from_ast(&fields.named, errors)?))
137 }
138 syn::Fields::Unnamed(ref fields: &FieldsUnnamed) => {
139 Ok((Style::Tuple, fields_from_ast(&fields.unnamed, errors)?))
140 }
141 syn::Fields::Unit => Ok((Style::Unit, Vec::new())),
142 }
143}
144
145fn 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 fieldsimpl Iterator>
150 .iter()
151 .map(|field: &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