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