1use internals::attr;
4use internals::check;
5use internals::{Ctxt, Derive};
6use syn;
7use syn::punctuated::Punctuated;
8
9pub struct Container<'a> {
12 pub ident: syn::Ident,
14 pub attrs: attr::Container,
16 pub data: Data<'a>,
18 pub generics: &'a syn::Generics,
20 pub original: &'a syn::DeriveInput,
22}
23
24pub enum Data<'a> {
28 Enum(Vec<Variant<'a>>),
29 Struct(Style, Vec<Field<'a>>),
30}
31
32pub struct Variant<'a> {
34 pub ident: syn::Ident,
35 pub attrs: attr::Variant,
36 pub style: Style,
37 pub fields: Vec<Field<'a>>,
38 pub original: &'a syn::Variant,
39}
40
41pub struct Field<'a> {
43 pub member: syn::Member,
44 pub attrs: attr::Field,
45 pub ty: &'a syn::Type,
46 pub original: &'a syn::Field,
47}
48
49#[derive(Copy, Clone)]
50pub enum Style {
51 Struct,
53 Tuple,
55 Newtype,
57 Unit,
59}
60
61impl<'a> Container<'a> {
62 pub fn from_ast(
64 cx: &Ctxt,
65 item: &'a syn::DeriveInput,
66 derive: Derive,
67 ) -> Option<Container<'a>> {
68 let mut attrs = attr::Container::from_ast(cx, item);
69
70 let mut data = match &item.data {
71 syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
72 syn::Data::Struct(data) => {
73 let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default());
74 Data::Struct(style, fields)
75 }
76 syn::Data::Union(_) => {
77 cx.error_spanned_by(item, "Serde does not support derive for unions");
78 return None;
79 }
80 };
81
82 let mut has_flatten = false;
83 match &mut data {
84 Data::Enum(variants) => {
85 for variant in variants {
86 variant.attrs.rename_by_rules(attrs.rename_all_rules());
87 for field in &mut variant.fields {
88 if field.attrs.flatten() {
89 has_flatten = true;
90 }
91 field
92 .attrs
93 .rename_by_rules(variant.attrs.rename_all_rules());
94 }
95 }
96 }
97 Data::Struct(_, fields) => {
98 for field in fields {
99 if field.attrs.flatten() {
100 has_flatten = true;
101 }
102 field.attrs.rename_by_rules(attrs.rename_all_rules());
103 }
104 }
105 }
106
107 if has_flatten {
108 attrs.mark_has_flatten();
109 }
110
111 let mut item = Container {
112 ident: item.ident.clone(),
113 attrs: attrs,
114 data: data,
115 generics: &item.generics,
116 original: item,
117 };
118 check::check(cx, &mut item, derive);
119 Some(item)
120 }
121}
122
123impl<'a> Data<'a> {
124 pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
125 match self {
126 Data::Enum(variants) => {
127 Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
128 }
129 Data::Struct(_, fields) => Box::new(fields.iter()),
130 }
131 }
132
133 pub fn has_getter(&self) -> bool {
134 self.all_fields().any(|f| f.attrs.getter().is_some())
135 }
136}
137
138fn enum_from_ast<'a>(
139 cx: &Ctxt,
140 variants: &'a Punctuated<syn::Variant, Token![,]>,
141 container_default: &attr::Default,
142) -> Vec<Variant<'a>> {
143 variants
144 .iter()
145 .map(|variant| {
146 let attrs = attr::Variant::from_ast(cx, variant);
147 let (style, fields) =
148 struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
149 Variant {
150 ident: variant.ident.clone(),
151 attrs: attrs,
152 style: style,
153 fields: fields,
154 original: variant,
155 }
156 })
157 .collect()
158}
159
160fn struct_from_ast<'a>(
161 cx: &Ctxt,
162 fields: &'a syn::Fields,
163 attrs: Option<&attr::Variant>,
164 container_default: &attr::Default,
165) -> (Style, Vec<Field<'a>>) {
166 match fields {
167 syn::Fields::Named(fields) => (
168 Style::Struct,
169 fields_from_ast(cx, &fields.named, attrs, container_default),
170 ),
171 syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
172 Style::Newtype,
173 fields_from_ast(cx, &fields.unnamed, attrs, container_default),
174 ),
175 syn::Fields::Unnamed(fields) => (
176 Style::Tuple,
177 fields_from_ast(cx, &fields.unnamed, attrs, container_default),
178 ),
179 syn::Fields::Unit => (Style::Unit, Vec::new()),
180 }
181}
182
183fn fields_from_ast<'a>(
184 cx: &Ctxt,
185 fields: &'a Punctuated<syn::Field, Token![,]>,
186 attrs: Option<&attr::Variant>,
187 container_default: &attr::Default,
188) -> Vec<Field<'a>> {
189 fields
190 .iter()
191 .enumerate()
192 .map(|(i, field)| Field {
193 member: match &field.ident {
194 Some(ident) => syn::Member::Named(ident.clone()),
195 None => syn::Member::Unnamed(i.into()),
196 },
197 attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
198 ty: &field.ty,
199 original: field,
200 })
201 .collect()
202}