1 | use std::borrow::Cow; |
2 | |
3 | use crate::ast::Fields; |
4 | use crate::codegen; |
5 | use crate::options::{Core, InputField, ParseAttribute}; |
6 | use crate::{Error, FromMeta, Result}; |
7 | |
8 | #[derive (Debug, Clone)] |
9 | pub struct InputVariant { |
10 | ident: syn::Ident, |
11 | attr_name: Option<String>, |
12 | data: Fields<InputField>, |
13 | skip: Option<bool>, |
14 | /// Whether or not unknown fields are acceptable in this |
15 | allow_unknown_fields: Option<bool>, |
16 | } |
17 | |
18 | impl InputVariant { |
19 | pub fn as_codegen_variant<'a>(&'a self, ty_ident: &'a syn::Ident) -> codegen::Variant<'a> { |
20 | codegen::Variant { |
21 | ty_ident, |
22 | variant_ident: &self.ident, |
23 | name_in_attr: self |
24 | .attr_name |
25 | .as_ref() |
26 | .map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed), |
27 | data: self.data.as_ref().map(InputField::as_codegen_field), |
28 | skip: self.skip.unwrap_or_default(), |
29 | allow_unknown_fields: self.allow_unknown_fields.unwrap_or_default(), |
30 | } |
31 | } |
32 | |
33 | pub fn from_variant(v: &syn::Variant, parent: Option<&Core>) -> Result<Self> { |
34 | let mut starter = (InputVariant { |
35 | ident: v.ident.clone(), |
36 | attr_name: Default::default(), |
37 | data: Fields::empty_from(&v.fields), |
38 | skip: Default::default(), |
39 | allow_unknown_fields: None, |
40 | }) |
41 | .parse_attributes(&v.attrs)?; |
42 | |
43 | starter.data.fields = match v.fields { |
44 | syn::Fields::Unit => vec![], |
45 | syn::Fields::Unnamed(ref fields) => { |
46 | let mut items = Vec::with_capacity(fields.unnamed.len()); |
47 | for item in &fields.unnamed { |
48 | items.push(InputField::from_field(item, parent)?); |
49 | } |
50 | |
51 | items |
52 | } |
53 | syn::Fields::Named(ref fields) => { |
54 | let mut items = Vec::with_capacity(fields.named.len()); |
55 | for item in &fields.named { |
56 | items.push(InputField::from_field(item, parent)?); |
57 | } |
58 | |
59 | items |
60 | } |
61 | }; |
62 | |
63 | Ok(if let Some(p) = parent { |
64 | starter.with_inherited(p) |
65 | } else { |
66 | starter |
67 | }) |
68 | } |
69 | |
70 | fn with_inherited(mut self, parent: &Core) -> Self { |
71 | if self.attr_name.is_none() { |
72 | self.attr_name = Some(parent.rename_rule.apply_to_variant(self.ident.to_string())); |
73 | } |
74 | |
75 | if self.allow_unknown_fields.is_none() { |
76 | self.allow_unknown_fields = Some(parent.allow_unknown_fields.unwrap_or_default()); |
77 | } |
78 | |
79 | self |
80 | } |
81 | } |
82 | |
83 | impl ParseAttribute for InputVariant { |
84 | fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { |
85 | let path: &Path = mi.path(); |
86 | if path.is_ident("rename" ) { |
87 | if self.attr_name.is_some() { |
88 | return Err(Error::duplicate_field_path(path).with_span(node:mi)); |
89 | } |
90 | |
91 | self.attr_name = FromMeta::from_meta(item:mi)?; |
92 | } else if path.is_ident("skip" ) { |
93 | if self.skip.is_some() { |
94 | return Err(Error::duplicate_field_path(path).with_span(node:mi)); |
95 | } |
96 | |
97 | self.skip = FromMeta::from_meta(item:mi)?; |
98 | } else { |
99 | return Err(Error::unknown_field_path(path).with_span(node:mi)); |
100 | } |
101 | |
102 | Ok(()) |
103 | } |
104 | } |
105 | |