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`. |
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> { |
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 | |
134 | pub fn has_getter(&self) -> bool { |
135 | self.all_fields().any(|f| f.attrs.getter().is_some()) |
136 | } |
137 | } |
138 | |
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 | |
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 | |
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 | |