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