1use proc_macro2::TokenStream;
2use quote::quote;
3use std::default::Default;
4use syn::{parse_quote, DeriveInput, Ident, Path, Visibility};
5
6use super::case_style::CaseStyle;
7use super::metadata::{DeriveInputExt, EnumDiscriminantsMeta, EnumMeta};
8use super::occurrence_error;
9
10pub trait HasTypeProperties {
11 fn get_type_properties(&self) -> syn::Result<StrumTypeProperties>;
12}
13
14#[derive(Debug, Clone, Default)]
15pub struct StrumTypeProperties {
16 pub case_style: Option<CaseStyle>,
17 pub ascii_case_insensitive: bool,
18 pub crate_module_path: Option<Path>,
19 pub discriminant_derives: Vec<Path>,
20 pub discriminant_name: Option<Ident>,
21 pub discriminant_others: Vec<TokenStream>,
22 pub discriminant_vis: Option<Visibility>,
23 pub use_phf: bool,
24}
25
26impl HasTypeProperties for DeriveInput {
27 fn get_type_properties(&self) -> syn::Result<StrumTypeProperties> {
28 let mut output = StrumTypeProperties::default();
29
30 let strum_meta = self.get_metadata()?;
31 let discriminants_meta = self.get_discriminants_metadata()?;
32
33 let mut serialize_all_kw = None;
34 let mut ascii_case_insensitive_kw = None;
35 let mut use_phf_kw = None;
36 let mut crate_module_path_kw = None;
37 for meta in strum_meta {
38 match meta {
39 EnumMeta::SerializeAll { case_style, kw } => {
40 if let Some(fst_kw) = serialize_all_kw {
41 return Err(occurrence_error(fst_kw, kw, "serialize_all"));
42 }
43
44 serialize_all_kw = Some(kw);
45 output.case_style = Some(case_style);
46 }
47 EnumMeta::AsciiCaseInsensitive(kw) => {
48 if let Some(fst_kw) = ascii_case_insensitive_kw {
49 return Err(occurrence_error(fst_kw, kw, "ascii_case_insensitive"));
50 }
51
52 ascii_case_insensitive_kw = Some(kw);
53 output.ascii_case_insensitive = true;
54 }
55 EnumMeta::UsePhf(kw) => {
56 if let Some(fst_kw) = use_phf_kw {
57 return Err(occurrence_error(fst_kw, kw, "use_phf"));
58 }
59
60 use_phf_kw = Some(kw);
61 output.use_phf = true;
62 }
63 EnumMeta::Crate {
64 crate_module_path,
65 kw,
66 } => {
67 if let Some(fst_kw) = crate_module_path_kw {
68 return Err(occurrence_error(fst_kw, kw, "Crate"));
69 }
70
71 crate_module_path_kw = Some(kw);
72 output.crate_module_path = Some(crate_module_path);
73 }
74 }
75 }
76
77 let mut name_kw = None;
78 let mut vis_kw = None;
79 for meta in discriminants_meta {
80 match meta {
81 EnumDiscriminantsMeta::Derive { paths, .. } => {
82 output.discriminant_derives.extend(paths);
83 }
84 EnumDiscriminantsMeta::Name { name, kw } => {
85 if let Some(fst_kw) = name_kw {
86 return Err(occurrence_error(fst_kw, kw, "name"));
87 }
88
89 name_kw = Some(kw);
90 output.discriminant_name = Some(name);
91 }
92 EnumDiscriminantsMeta::Vis { vis, kw } => {
93 if let Some(fst_kw) = vis_kw {
94 return Err(occurrence_error(fst_kw, kw, "vis"));
95 }
96
97 vis_kw = Some(kw);
98 output.discriminant_vis = Some(vis);
99 }
100 EnumDiscriminantsMeta::Other { path, nested } => {
101 output.discriminant_others.push(quote! { #path(#nested) });
102 }
103 }
104 }
105
106 Ok(output)
107 }
108}
109
110impl StrumTypeProperties {
111 pub fn crate_module_path(&self) -> Path {
112 self.crate_module_path
113 .as_ref()
114 .map_or_else(|| parse_quote!(::strum), |path: &Path| parse_quote!(#path))
115 }
116}
117