• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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> {
all_fields(&'a self) -> Box<dyn Iterator<Item = &'a Field<'a>> + 'a>114     pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a Field<'a>> + 'a> {
115         match self {
116             Data::Enum(variants) => {
117                 Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
118             }
119             Data::Struct(_, fields) => Box::new(fields.iter()),
120         }
121     }
122 
has_getter(&self) -> bool123     pub fn has_getter(&self) -> bool {
124         self.all_fields().any(|f| f.attrs.getter().is_some())
125     }
126 }
127 
enum_from_ast<'a>( cx: &Ctxt, variants: &'a Punctuated<syn::Variant, Token![,]>, container_default: &attr::Default, ) -> Vec<Variant<'a>>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 
struct_from_ast<'a>( cx: &Ctxt, fields: &'a syn::Fields, attrs: Option<&attr::Variant>, container_default: &attr::Default, ) -> (Style, Vec<Field<'a>>)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) => (
171             Style::Struct,
172             fields_from_ast(cx, &fields.named, attrs, container_default),
173         ),
174         syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
175             Style::Newtype,
176             fields_from_ast(cx, &fields.unnamed, attrs, container_default),
177         ),
178         syn::Fields::Unnamed(fields) => (
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 
fields_from_ast<'a>( cx: &Ctxt, fields: &'a Punctuated<syn::Field, Token![,]>, attrs: Option<&attr::Variant>, container_default: &attr::Default, ) -> Vec<Field<'a>>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     fields
193         .iter()
194         .enumerate()
195         .map(|(i, field)| Field {
196             member: match &field.ident {
197                 Some(ident) => syn::Member::Named(ident.clone()),
198                 None => syn::Member::Unnamed(i.into()),
199             },
200             attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
201             ty: &field.ty,
202             original: field,
203         })
204         .collect()
205 }
206