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 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 | match &mut data { |
81 | Data::Enum(variants) => { |
82 | for variant in variants { |
83 | variant.attrs.rename_by_rules(attrs.rename_all_rules()); |
84 | for field in &mut variant.fields { |
85 | field.attrs.rename_by_rules( |
86 | variant |
87 | .attrs |
88 | .rename_all_rules() |
89 | .or(attrs.rename_all_fields_rules()), |
90 | ); |
91 | } |
92 | } |
93 | } |
94 | Data::Struct(_, fields) => { |
95 | for field in fields { |
96 | field.attrs.rename_by_rules(attrs.rename_all_rules()); |
97 | } |
98 | } |
99 | } |
100 | |
101 | let mut item = Container { |
102 | ident: item.ident.clone(), |
103 | attrs, |
104 | data, |
105 | generics: &item.generics, |
106 | original: item, |
107 | }; |
108 | check::check(cx, &mut item, derive); |
109 | Some(item) |
110 | } |
111 | } |
112 | |
113 | impl<'a> Data<'a> { |
114 | pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a Field<'a>> + 'a> { |
115 | match self { |
116 | Data::Enum(variants: &Vec>) => { |
117 | Box::new(variants.iter().flat_map(|variant: &Variant<'_>| variant.fields.iter())) |
118 | } |
119 | Data::Struct(_, fields: &Vec>) => Box::new(fields.iter()), |
120 | } |
121 | } |
122 | |
123 | pub fn has_getter(&self) -> bool { |
124 | self.all_fields().any(|f: &Field<'_>| f.attrs.getter().is_some()) |
125 | } |
126 | } |
127 | |
128 | fn enum_from_ast<'a>( |
129 | cx: &Ctxt, |
130 | variants: &'a Punctuated<syn::Variant, Token![,]>, |
131 | container_default: &attr::Default, |
132 | ) -> Vec<Variant<'a>> { |
133 | let variants: Vec<Variant> = variants |
134 | .iter() |
135 | .map(|variant| { |
136 | let attrs = attr::Variant::from_ast(cx, variant); |
137 | let (style, fields) = |
138 | struct_from_ast(cx, &variant.fields, Some(&attrs), container_default); |
139 | Variant { |
140 | ident: variant.ident.clone(), |
141 | attrs, |
142 | style, |
143 | fields, |
144 | original: variant, |
145 | } |
146 | }) |
147 | .collect(); |
148 | |
149 | let index_of_last_tagged_variant = variants |
150 | .iter() |
151 | .rposition(|variant| !variant.attrs.untagged()); |
152 | if let Some(index_of_last_tagged_variant) = index_of_last_tagged_variant { |
153 | for variant in &variants[..index_of_last_tagged_variant] { |
154 | if variant.attrs.untagged() { |
155 | cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum" ); |
156 | } |
157 | } |
158 | } |
159 | |
160 | variants |
161 | } |
162 | |
163 | fn struct_from_ast<'a>( |
164 | cx: &Ctxt, |
165 | fields: &'a syn::Fields, |
166 | attrs: Option<&attr::Variant>, |
167 | container_default: &attr::Default, |
168 | ) -> (Style, Vec<Field<'a>>) { |
169 | match fields { |
170 | syn::Fields::Named(fields: &FieldsNamed) => ( |
171 | Style::Struct, |
172 | fields_from_ast(cx, &fields.named, attrs, container_default), |
173 | ), |
174 | syn::Fields::Unnamed(fields: &FieldsUnnamed) if fields.unnamed.len() == 1 => ( |
175 | Style::Newtype, |
176 | fields_from_ast(cx, &fields.unnamed, attrs, container_default), |
177 | ), |
178 | syn::Fields::Unnamed(fields: &FieldsUnnamed) => ( |
179 | Style::Tuple, |
180 | fields_from_ast(cx, &fields.unnamed, attrs, container_default), |
181 | ), |
182 | syn::Fields::Unit => (Style::Unit, Vec::new()), |
183 | } |
184 | } |
185 | |
186 | fn fields_from_ast<'a>( |
187 | cx: &Ctxt, |
188 | fields: &'a Punctuated<syn::Field, Token![,]>, |
189 | attrs: Option<&attr::Variant>, |
190 | container_default: &attr::Default, |
191 | ) -> Vec<Field<'a>> { |
192 | fieldsimpl Iterator- >
|
193 | .iter() |
194 | .enumerate() |
195 | .map(|(i: usize, field: &Field)| Field { |
196 | member: match &field.ident { |
197 | Some(ident: &Ident) => syn::Member::Named(ident.clone()), |
198 | None => syn::Member::Unnamed(i.into()), |
199 | }, |
200 | attrs: attr::Field::from_ast(cx, index:i, field, attrs, container_default), |
201 | ty: &field.ty, |
202 | original: field, |
203 | }) |
204 | .collect() |
205 | } |
206 | |