Skip to content

Commit 3bfbcf2

Browse files
authored
Merge pull request #23 from Swoorup/sj-grouping-syntax
Change grouped_matcher syntax to use `|` instead.
2 parents 8446f3c + 6d35480 commit 3bfbcf2

File tree

3 files changed

+37
-29
lines changed

3 files changed

+37
-29
lines changed

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# dtype_variant
32

43
A Rust derive macro for creating type-safe enum variants with shared type tokens across multiple enums. This enables synchronized variant types and powerful downcasting capabilities between related enums.
@@ -230,13 +229,13 @@ build_dtype_tokens!([Int, Float, Str]);
230229
#[dtype(tokens_path = self)]
231230
// Group variants by their logical category
232231
#[dtype_grouped_matcher(name = match_by_category, grouping = [
233-
Numeric([Int, Float]),
234-
Text([Str])
232+
Numeric(Int | Float),
233+
Text(Str)
235234
])]
236235
// Group variants by their memory footprint
237236
#[dtype_grouped_matcher(name = match_by_size, grouping = [
238-
Small([Int]),
239-
Large([Float, Str])
237+
Small(Int),
238+
Large(Float | Str)
240239
])]
241240
enum MyData {
242241
Int(i32),
@@ -312,3 +311,7 @@ Contributions are welcome! Please feel free to submit a Pull Request.
312311
## Acknowledgements
313312

314313
This project was inspired by [dtype_dispatch](https://github.com/pcodec/pcodec/tree/main/dtype_dispatch), which provides similar enum variant type dispatch functionality.
314+
315+
## Roadmap
316+
317+
- Add constraint support to the `grouped_matcher` argument for enforcing trait bounds on grouped variants.

dtype_variant/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,10 @@ mod tests {
148148
#[derive(DType, Debug, Clone, PartialEq)]
149149
#[dtype(tokens_path = self)] // skip_from_impls is false by default
150150
#[dtype_grouped_matcher(name = match_by_category, grouping = [
151-
Numeric([Int, Float]),
152-
Text([Str])
151+
Numeric(Int | Float),
152+
Text(Str)
153153
])]
154-
#[dtype_grouped_matcher(name = match_by_size, grouping = [Small([Int]), Large([Float, Str])])]
154+
#[dtype_grouped_matcher(name = match_by_size, grouping = [Small(Int), Large(Float | Str)])]
155155
#[allow(dead_code)]
156156
enum MyData {
157157
Int(i32),

dtype_variant_derive/src/grouped_matcher.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,44 +55,49 @@ impl FromMeta for ParsedGroups {
5555
_ => return Err(Error::custom("Expected group name identifier").with_span(&*call.func))
5656
};
5757

58-
// Ensure there's exactly one argument (the variant array)
58+
// Ensure there's exactly one argument (the variant expression)
5959
if call.args.len() != 1 {
6060
return Err(Error::custom(
61-
format!("Group `{}` expects exactly one argument (a list of variants in brackets `[...]`)", group_name)
61+
format!("Group `{}` expects exactly one argument (a list of variants separated by `|`)", group_name)
6262
).with_span(&call.args));
6363
}
6464

65-
// Extract the variants array
66-
let variants_array = match &call.args[0] {
67-
syn::Expr::Array(array) => array,
68-
_ => return Err(Error::custom(
69-
"Expected variant list in brackets `[...]`"
70-
).with_span(&call.args))
71-
};
72-
73-
// Extract each variant identifier
65+
// Extract the variants separated by `|`
66+
let variants_expr = &call.args[0];
7467
let mut variants = Vec::new();
75-
for variant_expr in &variants_array.elems {
76-
let variant = match variant_expr {
77-
syn::Expr::Path(path) => path.path.get_ident().cloned().ok_or_else(||
78-
Error::custom("Expected variant identifier").with_span(variant_expr)
79-
)?,
80-
_ => return Err(Error::unexpected_expr_type(variant_expr).with_span(variant_expr))
81-
};
82-
variants.push(variant);
68+
69+
fn extract_variants(expr: &syn::Expr, variants: &mut Vec<Ident>) -> darling::Result<()> {
70+
match expr {
71+
syn::Expr::Binary(binary) if matches!(binary.op, syn::BinOp::BitOr(_)) => {
72+
// Correctly handle `|` as a binary operator for separating variants
73+
extract_variants(&binary.left, variants)?;
74+
extract_variants(&binary.right, variants)?;
75+
}
76+
syn::Expr::Path(path) => {
77+
variants.push(path.path.get_ident().cloned().ok_or_else(||
78+
Error::custom("Expected variant identifier").with_span(path)
79+
)?);
80+
}
81+
_ => return Err(Error::custom(
82+
"Expected variants separated by `|` or a single variant identifier"
83+
).with_span(expr)),
84+
}
85+
Ok(())
8386
}
8487

88+
extract_variants(variants_expr, &mut variants)?;
89+
8590
// Ensure the variant list is not empty
8691
if variants.is_empty() {
8792
return Err(Error::custom(
8893
"Group variant list cannot be empty"
89-
).with_span(variants_array));
94+
).with_span(variants_expr));
9095
}
9196

9297
groups.push((group_name, variants));
9398
},
9499
_ => return Err(Error::custom(
95-
"Expected group definition in the format `GroupName([Variant, ...])`"
100+
"Expected group definition in the format `GroupName(Variant | ...)`"
96101
).with_span(elem))
97102
}
98103
}

0 commit comments

Comments
 (0)