strum_macros/helpers/
type_props.rs1use proc_macro2::TokenStream;
2use std::default::Default;
3use syn::{parse_quote, DeriveInput, Ident, LitStr, Meta, Path, Visibility};
4
5use super::case_style::CaseStyle;
6use super::metadata::{DeriveInputExt, EnumDiscriminantsMeta, EnumMeta};
7use super::occurrence_error;
8
9pub trait HasTypeProperties {
10 fn get_type_properties(&self) -> syn::Result<StrumTypeProperties>;
11}
12
13#[derive(Clone, Default)]
14pub struct StrumTypeProperties {
15 pub parse_err_ty: Option<Path>,
16 pub parse_err_fn: Option<Path>,
17 pub case_style: Option<CaseStyle>,
18 pub ascii_case_insensitive: bool,
19 pub crate_module_path: Option<Path>,
20 pub discriminant_derives: Vec<Path>,
21 pub discriminant_name: Option<Ident>,
22 pub discriminant_others: Vec<Meta>,
23 pub discriminant_vis: Option<Visibility>,
24 pub use_phf: bool,
25 pub prefix: Option<LitStr>,
26 pub suffix: Option<LitStr>,
27 pub enum_repr: Option<TokenStream>,
28 pub const_into_str: bool,
29}
30
31impl HasTypeProperties for DeriveInput {
32 fn get_type_properties(&self) -> syn::Result<StrumTypeProperties> {
33 let mut output = StrumTypeProperties::default();
34
35 let strum_meta = self.get_metadata()?;
36 let discriminants_meta = self.get_discriminants_metadata()?;
37
38 let mut parse_err_ty_kw = None;
39 let mut parse_err_fn_kw = None;
40 let mut serialize_all_kw = None;
41 let mut ascii_case_insensitive_kw = None;
42 let mut use_phf_kw = None;
43 let mut crate_module_path_kw = None;
44 let mut prefix_kw = None;
45 let mut suffix_kw = None;
46 let mut const_into_str = None;
47
48 for meta in strum_meta {
49 match meta {
50 EnumMeta::SerializeAll { case_style, kw } => {
51 if let Some(fst_kw) = serialize_all_kw {
52 return Err(occurrence_error(fst_kw, kw, "serialize_all"));
53 }
54
55 serialize_all_kw = Some(kw);
56 output.case_style = Some(case_style);
57 }
58 EnumMeta::AsciiCaseInsensitive(kw) => {
59 if let Some(fst_kw) = ascii_case_insensitive_kw {
60 return Err(occurrence_error(fst_kw, kw, "ascii_case_insensitive"));
61 }
62
63 ascii_case_insensitive_kw = Some(kw);
64 output.ascii_case_insensitive = true;
65 }
66 EnumMeta::UsePhf(kw) => {
67 if let Some(fst_kw) = use_phf_kw {
68 return Err(occurrence_error(fst_kw, kw, "use_phf"));
69 }
70
71 use_phf_kw = Some(kw);
72 output.use_phf = true;
73 }
74 EnumMeta::Crate {
75 crate_module_path,
76 kw,
77 } => {
78 if let Some(fst_kw) = crate_module_path_kw {
79 return Err(occurrence_error(fst_kw, kw, "Crate"));
80 }
81
82 crate_module_path_kw = Some(kw);
83 output.crate_module_path = Some(crate_module_path);
84 }
85 EnumMeta::Prefix { prefix, kw } => {
86 if let Some(fst_kw) = prefix_kw {
87 return Err(occurrence_error(fst_kw, kw, "prefix"));
88 }
89
90 prefix_kw = Some(kw);
91 output.prefix = Some(prefix);
92 }
93 EnumMeta::Suffix { suffix, kw } => {
94 if let Some(fst_kw) = suffix_kw {
95 return Err(occurrence_error(fst_kw, kw, "suffix"));
96 }
97
98 suffix_kw = Some(kw);
99 output.suffix = Some(suffix);
100 }
101 EnumMeta::ParseErrTy { path, kw } => {
102 if let Some(fst_kw) = parse_err_ty_kw {
103 return Err(occurrence_error(fst_kw, kw, "parse_err_ty"));
104 }
105
106 parse_err_ty_kw = Some(kw);
107 output.parse_err_ty = Some(path);
108 }
109 EnumMeta::ParseErrFn { path, kw } => {
110 if let Some(fst_kw) = parse_err_fn_kw {
111 return Err(occurrence_error(fst_kw, kw, "parse_err_fn"));
112 }
113
114 parse_err_fn_kw = Some(kw);
115 output.parse_err_fn = Some(path);
116 }
117 EnumMeta::ConstIntoStr(kw) => {
118 if let Some(fst_kw) = const_into_str {
119 return Err(occurrence_error(fst_kw, kw, "const_into_str"));
120 }
121
122 const_into_str = Some(kw);
123 output.const_into_str = true;
124 }
125 }
126 }
127
128 let mut name_kw = None;
129 let mut vis_kw = None;
130 for meta in discriminants_meta {
131 match meta {
132 EnumDiscriminantsMeta::Derive { paths, .. } => {
133 output.discriminant_derives.extend(paths);
134 }
135 EnumDiscriminantsMeta::Name { name, kw } => {
136 if let Some(fst_kw) = name_kw {
137 return Err(occurrence_error(fst_kw, kw, "name"));
138 }
139
140 name_kw = Some(kw);
141 output.discriminant_name = Some(name);
142 }
143 EnumDiscriminantsMeta::Vis { vis, kw } => {
144 if let Some(fst_kw) = vis_kw {
145 return Err(occurrence_error(fst_kw, kw, "vis"));
146 }
147
148 vis_kw = Some(kw);
149 output.discriminant_vis = Some(vis);
150 }
151 EnumDiscriminantsMeta::Other { passthrough_meta } => {
152 output.discriminant_others.push(passthrough_meta);
153 }
154 }
155 }
156
157 let attrs = &self.attrs;
158 for attr in attrs {
159 if let Ok(list) = attr.meta.require_list() {
160 if let Some(ident) = list.path.get_ident() {
161 if ident == "repr" {
162 output.enum_repr = Some(list.tokens.clone())
163 }
164 }
165 }
166 }
167
168 Ok(output)
169 }
170}
171
172impl StrumTypeProperties {
173 pub fn crate_module_path(&self) -> Path {
174 self.crate_module_path
175 .as_ref()
176 .map_or_else(|| parse_quote!(::strum), |path| parse_quote!(#path))
177 }
178}