strum_macros/helpers/
type_props.rs

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| parse_quote!(#path))
115    }
116}