1 | use proc_macro2::TokenStream; |
2 | use quote::quote; |
3 | use std::default::Default; |
4 | use syn::{parse_quote, DeriveInput, Ident, Path, Visibility}; |
5 | |
6 | use super::case_style::CaseStyle; |
7 | use super::metadata::{DeriveInputExt, EnumDiscriminantsMeta, EnumMeta}; |
8 | use super::occurrence_error; |
9 | |
10 | pub trait HasTypeProperties { |
11 | fn get_type_properties(&self) -> syn::Result<StrumTypeProperties>; |
12 | } |
13 | |
14 | #[derive (Debug, Clone, Default)] |
15 | pub 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 | |
26 | impl 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 | |
110 | impl 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 | |