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