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