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::util::SpannedValue;
7 use crate::{Error, FromMeta, Result};
8 
9 #[derive(Debug, Clone)]
10 pub struct InputVariant {
11     ident: syn::Ident,
12     attr_name: Option<String>,
13     data: Fields<InputField>,
14     skip: Option<bool>,
15     /// Whether or not the variant should be used to create an instance for
16     /// `FromMeta::from_word`.
17     pub word: Option<SpannedValue<bool>>,
18     /// Whether or not unknown fields are acceptable in this
19     allow_unknown_fields: Option<bool>,
20 }
21 
22 impl InputVariant {
as_codegen_variant<'a>(&'a self, ty_ident: &'a syn::Ident) -> codegen::Variant<'a>23     pub fn as_codegen_variant<'a>(&'a self, ty_ident: &'a syn::Ident) -> codegen::Variant<'a> {
24         codegen::Variant {
25             ty_ident,
26             variant_ident: &self.ident,
27             name_in_attr: self
28                 .attr_name
29                 .as_ref()
30                 .map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed),
31             data: self.data.as_ref().map(InputField::as_codegen_field),
32             skip: self.skip.unwrap_or_default(),
33             word: *self.word.unwrap_or_default(),
34             allow_unknown_fields: self.allow_unknown_fields.unwrap_or_default(),
35         }
36     }
37 
from_variant(v: &syn::Variant, parent: Option<&Core>) -> Result<Self>38     pub fn from_variant(v: &syn::Variant, parent: Option<&Core>) -> Result<Self> {
39         let mut starter = (InputVariant {
40             ident: v.ident.clone(),
41             attr_name: Default::default(),
42             data: Fields::empty_from(&v.fields),
43             skip: Default::default(),
44             word: Default::default(),
45             allow_unknown_fields: None,
46         })
47         .parse_attributes(&v.attrs)?;
48 
49         starter.data.fields = match v.fields {
50             syn::Fields::Unit => vec![],
51             syn::Fields::Unnamed(ref fields) => {
52                 let mut items = Vec::with_capacity(fields.unnamed.len());
53                 for item in &fields.unnamed {
54                     items.push(InputField::from_field(item, parent)?);
55                 }
56 
57                 items
58             }
59             syn::Fields::Named(ref fields) => {
60                 let mut items = Vec::with_capacity(fields.named.len());
61                 for item in &fields.named {
62                     items.push(InputField::from_field(item, parent)?);
63                 }
64 
65                 items
66             }
67         };
68 
69         Ok(if let Some(p) = parent {
70             starter.with_inherited(p)
71         } else {
72             starter
73         })
74     }
75 
with_inherited(mut self, parent: &Core) -> Self76     fn with_inherited(mut self, parent: &Core) -> Self {
77         if self.attr_name.is_none() {
78             self.attr_name = Some(parent.rename_rule.apply_to_variant(self.ident.to_string()));
79         }
80 
81         if self.allow_unknown_fields.is_none() {
82             self.allow_unknown_fields = Some(parent.allow_unknown_fields.unwrap_or_default());
83         }
84 
85         self
86     }
87 }
88 
89 impl ParseAttribute for InputVariant {
parse_nested(&mut self, mi: &syn::Meta) -> Result<()>90     fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
91         let path = mi.path();
92         if path.is_ident("rename") {
93             if self.attr_name.is_some() {
94                 return Err(Error::duplicate_field_path(path).with_span(mi));
95             }
96 
97             self.attr_name = FromMeta::from_meta(mi)?;
98         } else if path.is_ident("skip") {
99             if self.skip.is_some() {
100                 return Err(Error::duplicate_field_path(path).with_span(mi));
101             }
102 
103             self.skip = FromMeta::from_meta(mi)?;
104         } else if path.is_ident("word") {
105             if self.word.is_some() {
106                 return Err(Error::duplicate_field_path(path).with_span(mi));
107             }
108 
109             if !self.data.is_unit() {
110                 let note = "`#[darling(word)]` can only be applied to a unit variant";
111                 #[cfg(feature = "diagnostics")]
112                 let error = Error::unknown_field_path(path).note(note);
113                 #[cfg(not(feature = "diagnostics"))]
114                 let error = Error::custom(format!("Unexpected field: `word`. {}", note));
115 
116                 return Err(error.with_span(mi));
117             }
118 
119             self.word = FromMeta::from_meta(mi)?;
120         } else {
121             return Err(Error::unknown_field_path(path).with_span(mi));
122         }
123 
124         Ok(())
125     }
126 }
127