Skip to content

Commit 4ab4e7c

Browse files
committed
Refactor derive macro's input parsing
1 parent f588ca6 commit 4ab4e7c

File tree

22 files changed

+257
-236
lines changed

22 files changed

+257
-236
lines changed

macros/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ proc-macro = true
2020
[dependencies]
2121
proc-macro2 = { version = "1.0.81", features = ["span-locations"] }
2222
quote = "1.0.36"
23-
syn = { version = "2.0.60", features = ["derive", "visit"] }
23+
syn = { version = "2.0.60", features = ["full", "visit"] }

macros/src/config.rs

Lines changed: 77 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,57 @@ pub(crate) enum VariantFieldConfig {
3030
Index(usize),
3131
}
3232

33-
#[derive(Clone, Default, Debug)]
33+
#[derive(Clone, Default, PartialEq, Eq, Debug)]
34+
pub(crate) struct MacroSelectionConfig {
35+
pub idents: Vec<syn::Ident>,
36+
}
37+
38+
impl MacroSelectionConfig {
39+
pub fn is_empty(&self) -> bool {
40+
self.idents.is_empty()
41+
}
42+
43+
pub fn contains(&self, name: &str) -> bool {
44+
self.idents.iter().any(|ident| ident == name)
45+
}
46+
47+
pub fn extend_idents(&mut self, iter: impl IntoIterator<Item = syn::Ident>) {
48+
self.idents.extend(iter);
49+
}
50+
51+
pub(crate) fn idents(&self) -> &[syn::Ident] {
52+
&self.idents
53+
}
54+
}
55+
56+
pub(crate) type EnumExcludeConfig = MacroSelectionConfig;
57+
pub(crate) type VariantExcludeConfig = MacroSelectionConfig;
58+
pub(crate) type VariantIncludeConfig = MacroSelectionConfig;
59+
60+
#[derive(Clone, Default)]
3461
pub(crate) struct EnumConfig {
3562
// #[enumcapsulate(exclude(…))]
36-
pub exclude: Option<Vec<syn::Ident>>,
63+
pub exclude: Option<EnumExcludeConfig>,
3764
}
3865

3966
impl EnumConfig {
4067
pub fn is_excluded(&self, name: &str) -> bool {
41-
if let Some(excluded) = &self.exclude {
42-
return excluded.iter().any(|ident| ident == name);
43-
} else {
44-
false
45-
}
68+
self.exclude
69+
.as_ref()
70+
.map(|excluded| excluded.contains(name))
71+
.unwrap_or(false)
4672
}
4773
}
4874

49-
#[derive(Clone, Default, Debug)]
75+
#[derive(Clone, Default)]
5076
pub(crate) struct VariantConfig {
5177
// #[enumcapsulate(exclude(…))]
52-
pub exclude: Option<Vec<syn::Ident>>,
78+
pub exclude: Option<VariantExcludeConfig>,
5379

5480
// #[enumcapsulate(include(…))]
55-
pub include: Option<Vec<syn::Ident>>,
81+
pub include: Option<VariantIncludeConfig>,
5682

57-
// #[enumcapsulate(field(… = …))]
83+
// #[enumcapsulate(field(…))]
5884
pub field: Option<VariantFieldConfig>,
5985
}
6086

@@ -73,49 +99,48 @@ impl VariantConfig {
7399
}
74100

75101
pub fn is_excluded_explicitly(&self, name: &str) -> bool {
76-
if let Some(excluded) = &self.exclude {
77-
if excluded.is_empty() {
78-
if let Some(included) = &self.include {
79-
return !included.iter().any(|ident| ident == name);
80-
} else {
81-
return true;
82-
}
83-
}
102+
let Some(excluded) = &self.exclude else {
103+
return false;
104+
};
84105

85-
excluded.iter().any(|ident| ident == name)
86-
} else {
87-
false
106+
if excluded.is_empty() {
107+
if let Some(included) = &self.include {
108+
return !included.contains(name);
109+
} else {
110+
return true;
111+
}
88112
}
113+
114+
excluded.contains(name)
89115
}
90116

91117
pub fn is_included_explicitly(&self, name: &str) -> bool {
92-
if let Some(included) = &self.include {
93-
if included.is_empty() {
94-
if let Some(excluded) = &self.exclude {
95-
return !excluded.iter().any(|ident| ident == name);
96-
} else {
97-
return true;
98-
}
99-
}
118+
let Some(included) = &self.include else {
119+
return false;
120+
};
100121

101-
included.iter().any(|ident| ident == name)
102-
} else {
103-
false
122+
if included.is_empty() {
123+
if let Some(excluded) = &self.exclude {
124+
return !excluded.contains(name);
125+
} else {
126+
return true;
127+
}
104128
}
129+
130+
included.contains(name)
105131
}
106132
}
107133

108-
pub(crate) fn config_for_enum_with_attrs(
109-
enum_attrs: &[syn::Attribute],
110-
) -> Result<EnumConfig, syn::Error> {
134+
pub(crate) fn config_for_enum(enum_item: &syn::ItemEnum) -> Result<EnumConfig, syn::Error> {
111135
let mut config = EnumConfig::default();
112136

113-
parse_enumcapsulate_attrs(enum_attrs, |meta| {
137+
parse_enumcapsulate_attrs(&enum_item.attrs, |meta| {
114138
if meta.path.is_ident(attr::EXCLUDE) {
115139
// #[enumcapsulate(exclude(…))]
116140

117141
let mut exclude = config.exclude.take().unwrap_or_default();
118-
exclude.extend(macro_idents_for_enum(&meta)?.into_iter());
142+
exclude.extend_idents(macro_selection_config_for_enum(&meta)?.idents);
143+
119144
config.exclude = Some(exclude);
120145
} else {
121146
return Err(meta.error("unrecognized attribute"));
@@ -141,17 +166,19 @@ pub(crate) fn config_for_variant(variant: &syn::Variant) -> Result<VariantConfig
141166
// #[enumcapsulate(exclude(…))]
142167

143168
let mut exclude = config.exclude.take().unwrap_or_default();
144-
let conflicting = config.include.as_deref().unwrap_or(&[]);
145169

146-
exclude.extend(macro_idents_for_variant(&meta, conflicting)?.into_iter());
170+
let opposite = config.include.as_ref();
171+
exclude.extend_idents(macro_selection_config_for_variant(&meta, opposite)?.idents);
172+
147173
config.exclude = Some(exclude);
148174
} else if meta.path.is_ident(attr::INCLUDE) {
149175
// #[enumcapsulate(include(…))]
150176

151177
let mut include = config.include.take().unwrap_or_default();
152-
let conflicting = config.exclude.as_deref().unwrap_or(&[]);
153178

154-
include.extend(macro_idents_for_variant(&meta, conflicting)?.into_iter());
179+
let opposite: Option<&MacroSelectionConfig> = config.exclude.as_ref();
180+
include.extend_idents(macro_selection_config_for_variant(&meta, opposite)?.idents);
181+
155182
config.include = Some(include);
156183
} else if meta.path.is_ident(attr::FIELD) {
157184
// #[enumcapsulate(field(…))]
@@ -233,29 +260,30 @@ pub(crate) fn parse_enumcapsulate_attrs(
233260
Ok(())
234261
}
235262

236-
pub(crate) fn macro_idents_for_enum(
263+
pub(crate) fn macro_selection_config_for_enum(
237264
meta: &syn::meta::ParseNestedMeta<'_>,
238-
) -> Result<Vec<syn::Ident>, syn::Error> {
265+
) -> Result<MacroSelectionConfig, syn::Error> {
239266
let idents = parse_idents_from_meta_list(meta)?;
240267

241268
let recognized = RECOGNIZED_ENUM_LEVEL_MACROS;
242269
ensure_only_recognized_ident_names(&idents, recognized)?;
243270

244-
Ok(idents)
271+
Ok(MacroSelectionConfig { idents })
245272
}
246273

247-
pub(crate) fn macro_idents_for_variant(
274+
pub(crate) fn macro_selection_config_for_variant(
248275
meta: &syn::meta::ParseNestedMeta<'_>,
249-
conflict_list: &[syn::Ident],
250-
) -> Result<Vec<syn::Ident>, syn::Error> {
276+
opposite: Option<&MacroSelectionConfig>,
277+
) -> Result<MacroSelectionConfig, syn::Error> {
251278
let idents = parse_idents_from_meta_list(meta)?;
252279

253280
let recognized = RECOGNIZED_VARIANT_LEVEL_MACROS;
254281
ensure_only_recognized_ident_names(&idents, recognized)?;
255282

283+
let conflict_list = opposite.map(|config| config.idents()).unwrap_or(&[]);
256284
ensure_no_conflicting_idents(&idents, conflict_list)?;
257285

258-
Ok(idents)
286+
Ok(MacroSelectionConfig { idents })
259287
}
260288

261289
pub(crate) fn ensure_only_recognized_ident_names(

0 commit comments

Comments
 (0)