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