1use crate::internals::{attr, check, Ctxt, Derive};
4use syn::punctuated::Punctuated;
5use syn::Token;
6
7pub struct Container<'a> {
10 pub ident: syn::Ident,
12 pub attrs: attr::Container,
14 pub data: Data<'a>,
16 pub generics: &'a syn::Generics,
18 pub original: &'a syn::DeriveInput,
20}
21
22pub enum Data<'a> {
26 Enum(Vec<Variant<'a>>),
27 Struct(Style, Vec<Field<'a>>),
28}
29
30pub 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
39pub 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 Struct,
51 Tuple,
53 Newtype,
55 Unit,
57}
58
59impl<'a> Container<'a> {
60 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
113impl<'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) => {
117 Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
118 }
119 Data::Struct(_, fields) => Box::new(fields.iter()),
120 }
121 }
122
123 pub fn has_getter(&self) -> bool {
124 self.all_fields().any(|f| f.attrs.getter().is_some())
125 }
126}
127
128fn 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
163fn 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
186fn 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}