1 //! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
2 
3 use crate::internals::{attr, check, Ctxt, Derive};
4 use syn::punctuated::Punctuated;
5 use syn::Token;
6 
7 /// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`,
8 /// parsed into an internal representation.
9 pub struct Container<'a> {
10     /// The struct or enum name (without generics).
11     pub ident: syn::Ident,
12     /// Attributes on the structure, parsed for Serde.
13     pub attrs: attr::Container,
14     /// The contents of the struct or enum.
15     pub data: Data<'a>,
16     /// Any generics on the struct or enum.
17     pub generics: &'a syn::Generics,
18     /// Original input.
19     pub original: &'a syn::DeriveInput,
20 }
21 
22 /// The fields of a struct or enum.
23 ///
24 /// Analogous to `syn::Data`.
25 pub enum Data<'a> {
26     Enum(Vec<Variant<'a>>),
27     Struct(Style, Vec<Field<'a>>),
28 }
29 
30 /// A variant of an enum.
31 pub struct Variant<'a> {
32     pub ident: syn::Ident,
33     pub attrs: attr::Variant,
34     pub style: Style,
35     pub fields: Vec<Field<'a>>,
36     pub original: &'a syn::Variant,
37 }
38 
39 /// A field of a struct.
40 pub struct Field<'a> {
41     pub member: syn::Member,
42     pub attrs: attr::Field,
43     pub ty: &'a syn::Type,
44     pub original: &'a syn::Field,
45 }
46 
47 #[derive(Copy, Clone)]
48 pub enum Style {
49     /// Named fields.
50     Struct,
51     /// Many unnamed fields.
52     Tuple,
53     /// One unnamed field.
54     Newtype,
55     /// No fields.
56     Unit,
57 }
58 
59 impl<'a> Container<'a> {
60     /// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`.
from_ast( cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive, ) -> Option<Container<'a>>61     pub fn from_ast(
62         cx: &Ctxt,
63         item: &'a syn::DeriveInput,
64         derive: Derive,
65     ) -> Option<Container<'a>> {
66         let mut attrs = attr::Container::from_ast(cx, item);
67 
68         let mut data = match &item.data {
69             syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
70             syn::Data::Struct(data) => {
71                 let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default());
72                 Data::Struct(style, fields)
73             }
74             syn::Data::Union(_) => {
75                 cx.error_spanned_by(item, "Serde does not support derive for unions");
76                 return None;
77             }
78         };
79 
80         let mut has_flatten = false;
81         match &mut data {
82             Data::Enum(variants) => {
83                 for variant in variants {
84                     variant.attrs.rename_by_rules(attrs.rename_all_rules());
85                     for field in &mut variant.fields {
86                         if field.attrs.flatten() {
87                             has_flatten = true;
88                         }
89                         field.attrs.rename_by_rules(
90                             variant
91                                 .attrs
92                                 .rename_all_rules()
93                                 .or(attrs.rename_all_fields_rules()),
94                         );
95                     }
96                 }
97             }
98             Data::Struct(_, fields) => {
99                 for field in fields {
100                     if field.attrs.flatten() {
101                         has_flatten = true;
102                     }
103                     field.attrs.rename_by_rules(attrs.rename_all_rules());
104                 }
105             }
106         }
107 
108         if has_flatten {
109             attrs.mark_has_flatten();
110         }
111 
112         let mut item = Container {
113             ident: item.ident.clone(),
114             attrs,
115             data,
116             generics: &item.generics,
117             original: item,
118         };
119         check::check(cx, &mut item, derive);
120         Some(item)
121     }
122 }
123 
124 impl<'a> Data<'a> {
all_fields(&'a self) -> Box<dyn Iterator<Item = &'a Field<'a>> + 'a>125     pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a Field<'a>> + 'a> {
126         match self {
127             Data::Enum(variants) => {
128                 Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
129             }
130             Data::Struct(_, fields) => Box::new(fields.iter()),
131         }
132     }
133 
has_getter(&self) -> bool134     pub fn has_getter(&self) -> bool {
135         self.all_fields().any(|f| f.attrs.getter().is_some())
136     }
137 }
138 
enum_from_ast<'a>( cx: &Ctxt, variants: &'a Punctuated<syn::Variant, Token![,]>, container_default: &attr::Default, ) -> Vec<Variant<'a>>139 fn enum_from_ast<'a>(
140     cx: &Ctxt,
141     variants: &'a Punctuated<syn::Variant, Token![,]>,
142     container_default: &attr::Default,
143 ) -> Vec<Variant<'a>> {
144     let variants: Vec<Variant> = variants
145         .iter()
146         .map(|variant| {
147             let attrs = attr::Variant::from_ast(cx, variant);
148             let (style, fields) =
149                 struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
150             Variant {
151                 ident: variant.ident.clone(),
152                 attrs,
153                 style,
154                 fields,
155                 original: variant,
156             }
157         })
158         .collect();
159 
160     let index_of_last_tagged_variant = variants
161         .iter()
162         .rposition(|variant| !variant.attrs.untagged());
163     if let Some(index_of_last_tagged_variant) = index_of_last_tagged_variant {
164         for variant in &variants[..index_of_last_tagged_variant] {
165             if variant.attrs.untagged() {
166                 cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum");
167             }
168         }
169     }
170 
171     variants
172 }
173 
struct_from_ast<'a>( cx: &Ctxt, fields: &'a syn::Fields, attrs: Option<&attr::Variant>, container_default: &attr::Default, ) -> (Style, Vec<Field<'a>>)174 fn struct_from_ast<'a>(
175     cx: &Ctxt,
176     fields: &'a syn::Fields,
177     attrs: Option<&attr::Variant>,
178     container_default: &attr::Default,
179 ) -> (Style, Vec<Field<'a>>) {
180     match fields {
181         syn::Fields::Named(fields) => (
182             Style::Struct,
183             fields_from_ast(cx, &fields.named, attrs, container_default),
184         ),
185         syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
186             Style::Newtype,
187             fields_from_ast(cx, &fields.unnamed, attrs, container_default),
188         ),
189         syn::Fields::Unnamed(fields) => (
190             Style::Tuple,
191             fields_from_ast(cx, &fields.unnamed, attrs, container_default),
192         ),
193         syn::Fields::Unit => (Style::Unit, Vec::new()),
194     }
195 }
196 
fields_from_ast<'a>( cx: &Ctxt, fields: &'a Punctuated<syn::Field, Token![,]>, attrs: Option<&attr::Variant>, container_default: &attr::Default, ) -> Vec<Field<'a>>197 fn fields_from_ast<'a>(
198     cx: &Ctxt,
199     fields: &'a Punctuated<syn::Field, Token![,]>,
200     attrs: Option<&attr::Variant>,
201     container_default: &attr::Default,
202 ) -> Vec<Field<'a>> {
203     fields
204         .iter()
205         .enumerate()
206         .map(|(i, field)| Field {
207             member: match &field.ident {
208                 Some(ident) => syn::Member::Named(ident.clone()),
209                 None => syn::Member::Unnamed(i.into()),
210             },
211             attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
212             ty: &field.ty,
213             original: field,
214         })
215         .collect()
216 }
217