• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::default::Default;
2 use syn::{Ident, Lit, LitStr, Variant};
3 
4 use super::case_style::{CaseStyle, CaseStyleHelpers};
5 use super::metadata::{kw, VariantExt, VariantMeta};
6 use super::occurrence_error;
7 
8 pub trait HasStrumVariantProperties {
get_variant_properties(&self) -> syn::Result<StrumVariantProperties>9     fn get_variant_properties(&self) -> syn::Result<StrumVariantProperties>;
10 }
11 
12 #[derive(Clone, Default)]
13 pub struct StrumVariantProperties {
14     pub transparent: Option<kw::transparent>,
15     pub disabled: Option<kw::disabled>,
16     pub default: Option<kw::default>,
17     pub default_with: Option<LitStr>,
18     pub ascii_case_insensitive: Option<bool>,
19     pub message: Option<LitStr>,
20     pub detailed_message: Option<LitStr>,
21     pub documentation: Vec<LitStr>,
22     pub props: Vec<(LitStr, Lit)>,
23     serialize: Vec<LitStr>,
24     pub to_string: Option<LitStr>,
25     ident: Option<Ident>,
26 }
27 
28 impl StrumVariantProperties {
ident_as_str(&self, case_style: Option<CaseStyle>) -> LitStr29     fn ident_as_str(&self, case_style: Option<CaseStyle>) -> LitStr {
30         let ident = self.ident.as_ref().expect("identifier");
31         LitStr::new(&ident.convert_case(case_style), ident.span())
32     }
33 
get_preferred_name( &self, case_style: Option<CaseStyle>, prefix: Option<&LitStr>, ) -> LitStr34     pub fn get_preferred_name(
35         &self,
36         case_style: Option<CaseStyle>,
37         prefix: Option<&LitStr>,
38     ) -> LitStr {
39         let mut output = self.to_string.as_ref().cloned().unwrap_or_else(|| {
40             self.serialize
41                 .iter()
42                 .max_by_key(|s| s.value().len())
43                 .cloned()
44                 .unwrap_or_else(|| self.ident_as_str(case_style))
45         });
46 
47         if let Some(prefix) = prefix {
48             output = LitStr::new(&(prefix.value() + &output.value()), output.span());
49         }
50 
51         output
52     }
53 
get_serializations(&self, case_style: Option<CaseStyle>) -> Vec<LitStr>54     pub fn get_serializations(&self, case_style: Option<CaseStyle>) -> Vec<LitStr> {
55         let mut attrs = self.serialize.clone();
56         if let Some(to_string) = &self.to_string {
57             attrs.push(to_string.clone());
58         }
59 
60         if attrs.is_empty() {
61             attrs.push(self.ident_as_str(case_style));
62         }
63 
64         attrs
65     }
66 }
67 
68 impl HasStrumVariantProperties for Variant {
get_variant_properties(&self) -> syn::Result<StrumVariantProperties>69     fn get_variant_properties(&self) -> syn::Result<StrumVariantProperties> {
70         let mut output = StrumVariantProperties {
71             ident: Some(self.ident.clone()),
72             ..Default::default()
73         };
74 
75         let mut message_kw = None;
76         let mut detailed_message_kw = None;
77         let mut transparent_kw = None;
78         let mut disabled_kw = None;
79         let mut default_kw = None;
80         let mut default_with_kw = None;
81         let mut to_string_kw = None;
82         let mut ascii_case_insensitive_kw = None;
83         for meta in self.get_metadata()? {
84             match meta {
85                 VariantMeta::Message { value, kw } => {
86                     if let Some(fst_kw) = message_kw {
87                         return Err(occurrence_error(fst_kw, kw, "message"));
88                     }
89 
90                     message_kw = Some(kw);
91                     output.message = Some(value);
92                 }
93                 VariantMeta::DetailedMessage { value, kw } => {
94                     if let Some(fst_kw) = detailed_message_kw {
95                         return Err(occurrence_error(fst_kw, kw, "detailed_message"));
96                     }
97 
98                     detailed_message_kw = Some(kw);
99                     output.detailed_message = Some(value);
100                 }
101                 VariantMeta::Documentation { value } => {
102                     output.documentation.push(value);
103                 }
104                 VariantMeta::Serialize { value, .. } => {
105                     output.serialize.push(value);
106                 }
107                 VariantMeta::ToString { value, kw } => {
108                     if let Some(fst_kw) = to_string_kw {
109                         return Err(occurrence_error(fst_kw, kw, "to_string"));
110                     }
111 
112                     to_string_kw = Some(kw);
113                     output.to_string = Some(value);
114                 }
115                 VariantMeta::Transparent(kw) => {
116                     if let Some(fst_kw) = transparent_kw {
117                         return Err(occurrence_error(fst_kw, kw, "transparent"));
118                     }
119 
120                     transparent_kw = Some(kw);
121                     output.transparent = Some(kw);
122                 }
123                 VariantMeta::Disabled(kw) => {
124                     if let Some(fst_kw) = disabled_kw {
125                         return Err(occurrence_error(fst_kw, kw, "disabled"));
126                     }
127 
128                     disabled_kw = Some(kw);
129                     output.disabled = Some(kw);
130                 }
131                 VariantMeta::Default(kw) => {
132                     if let Some(fst_kw) = default_kw {
133                         return Err(occurrence_error(fst_kw, kw, "default"));
134                     }
135 
136                     default_kw = Some(kw);
137                     output.default = Some(kw);
138                 }
139                 VariantMeta::DefaultWith { kw, value } => {
140                     if let Some(fst_kw) = default_with_kw {
141                         return Err(occurrence_error(fst_kw, kw, "default_with"));
142                     }
143 
144                     default_with_kw = Some(kw);
145                     output.default_with = Some(value);
146                 }
147                 VariantMeta::AsciiCaseInsensitive { kw, value } => {
148                     if let Some(fst_kw) = ascii_case_insensitive_kw {
149                         return Err(occurrence_error(fst_kw, kw, "ascii_case_insensitive"));
150                     }
151 
152                     ascii_case_insensitive_kw = Some(kw);
153                     output.ascii_case_insensitive = Some(value);
154                 }
155                 VariantMeta::Props { props, .. } => {
156                     output.props.extend(props);
157                 }
158             }
159         }
160 
161         Ok(output)
162     }
163 }
164