serde_derive_internals/src/
ast.rs

1//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
2
3use crate::internals::{attr, check, Ctxt, Derive};
4use syn::punctuated::Punctuated;
5use syn::Token;
6
7/// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`,
8/// parsed into an internal representation.
9pub 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`.
25pub enum Data<'a> {
26    Enum(Vec<Variant<'a>>),
27    Struct(Style, Vec<Field<'a>>),
28}
29
30/// A variant of an enum.
31pub 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.
40pub 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)]
48pub 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
59impl<'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
124impl<'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
139fn 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
174fn 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
197fn 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}