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