Skip to content

Commit 90b5485

Browse files
committed
match_class! now uses var @ Class syntax
1 parent 8a4e5a1 commit 90b5485

File tree

2 files changed

+56
-53
lines changed

2 files changed

+56
-53
lines changed

godot-core/src/classes/match_class.rs

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
///
1414
/// Requires a fallback branch, even if all direct known classes are handled. The reason for this is that there may be other subclasses which
1515
/// are not statically known by godot-rust (e.g. from a script or GDExtension). The fallback branch can either be `_` (discard object), or
16-
/// `_(variable)` to access the original object inside the fallback arm.
16+
/// `variable @ _` to access the original object inside the fallback arm.
1717
///
1818
/// # Example
1919
/// ```no_run
@@ -27,28 +27,28 @@
2727
/// let event: Gd<InputEvent> = some_input();
2828
///
2929
/// let simple_dispatch: i32 = match_class!(event, {
30-
/// InputEventMouseButton(btn) => 1,
31-
/// InputEventMouseMotion(motion) => 2,
32-
/// InputEventAction(action) => 3,
30+
/// button @ InputEventMouseButton => 1,
31+
/// motion @ InputEventMouseMotion => 2,
32+
/// action @ InputEventAction => 3,
3333
/// _ => 0, // Fallback.
3434
/// });
3535
///
3636
/// // More diverse dispatch patterns are also supported.
3737
/// let fancy_dispatch: i32 = match_class!(some_input(), {
38-
/// InputEventMouseButton(btn) => 1,
38+
/// button @ InputEventMouseButton => 1,
3939
///
4040
/// // Block syntax for multiple statements:
41-
/// InputEventMouseMotion(motion) => {
41+
/// motion @ InputEventMouseMotion => {
4242
/// godot_print!("motion");
4343
/// 2
4444
/// },
4545
///
4646
/// // Qualified types supported:
47-
/// godot::classes::InputEventAction(action) => 3,
47+
/// action @ godot::classes::InputEventAction => 3,
4848
///
4949
/// // Fallback with variable -- retrieves original Gd<InputEvent>.
50-
/// // Equivalent to pattern `InputEvent(original)`.
51-
/// _(original) => 0,
50+
/// // Equivalent to pattern `original @ InputEvent`.
51+
/// original @ _ => 0,
5252
/// });
5353
///
5454
/// // event_type is now 0, 1, 2, or 3
@@ -60,42 +60,45 @@
6060
// Note: annoyingly shows full implementation in docs. For workarounds, either move impl to a helper macro, or use something like
6161
// https://crates.io/crates/clean-macro-docs.
6262
macro_rules! match_class {
63-
($subject:expr, {
64-
$(
65-
$($class:ident)::+($var:ident) => $body:expr
66-
),+,
67-
_($fallback_var:ident) => $fallback:expr
68-
$(,)?
69-
}) => {
63+
// TT muncher approach: consume one arm at a time and recurse with the remaining tokens.
64+
65+
// Entry point: grab subject + ENTIRE list of arms as token-trees.
66+
($subject:expr, { $($arms:tt)* }) => {
7067
(|| {
71-
let mut __evt = $subject;
72-
$(
73-
__evt = match __evt.try_cast::<$($class)::*>() {
74-
Ok($var) => return $body,
75-
Err(e) => e,
76-
};
77-
)+
78-
let $fallback_var = __evt;
79-
$fallback
68+
let mut __match_subject = $subject;
69+
match_class!(@munch __match_subject; $($arms)*);
70+
// unreachable!("match_class hit end with no `_` fallback");
8071
})()
8172
};
8273

83-
($subject:expr, {
84-
$(
85-
$($class:ident)::+($var:ident) => $body:expr
86-
),+,
87-
_ => $fallback:expr
74+
// ident @ Some::Path => expr, rest...
75+
(@munch $evt:ident;
76+
$var:ident @ $($class:ident)::+ => $body:expr,
77+
$($rest:tt)*
78+
) => {
79+
// try the down‐cast
80+
$evt = match $evt.try_cast::< $($class)::* >() {
81+
Ok($var) => return $body,
82+
Err(e) => e,
83+
};
84+
match_class!(@munch $evt; $($rest)*);
85+
};
86+
87+
// foo @ _ => expr
88+
(@munch $evt:ident;
89+
$fallback_var:ident @ $pat:tt => $fallback:expr
8890
$(,)?
89-
}) => {
90-
(|| {
91-
let mut __evt = $subject;
92-
$(
93-
__evt = match __evt.try_cast::<$($class)::*>() {
94-
Ok($var) => return $body,
95-
Err(e) => e,
96-
};
97-
)+
98-
$fallback
99-
})()
91+
) => {
92+
// `$pat` here will only ever be `_` if no typed‐arm matched first, because `Some::Path` would hit the more specific rule above.
93+
let $fallback_var = $evt;
94+
return $fallback;
10095
};
96+
97+
// _ => expr
98+
(@munch $evt:ident;
99+
_ => $fallback:expr
100+
$(,)?
101+
) => {{
102+
return $fallback;
103+
}};
101104
}

itest/rust/src/engine_tests/match_class_test.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ fn match_class_basic_dispatch() {
2020
let to_free = obj.clone();
2121

2222
let result = match_class!(obj, {
23-
Node2D(node) => {
23+
node @ Node2D => {
2424
require_node2d(&node);
2525
1
2626
},
27-
Node(node) => {
27+
node @ Node => {
2828
require_node(&node);
2929
2
3030
},
@@ -42,8 +42,8 @@ fn match_class_shadowed_by_more_general() {
4242
let to_free = obj.clone();
4343

4444
let result = match_class!(obj, {
45-
Node(_node) => 1,
46-
Node2D(_node) => 2,
45+
_node @ Node => 1,
46+
_node @ Node2D => 2,
4747
_ => 3, // Comma.
4848
});
4949

@@ -59,8 +59,8 @@ fn match_class_ignored_fallback() {
5959
let obj: Gd<Object> = RefCounted::new_gd().upcast();
6060

6161
let result = match_class!(obj, {
62-
godot::classes::Node(_node) => 1, // Test qualified types.
63-
Resource(_res) => 2,
62+
_node @ godot::classes::Node => 1, // Test qualified types.
63+
_res @ Resource => 2,
6464
_ => 3,
6565
});
6666

@@ -72,11 +72,11 @@ fn match_class_named_fallback_matched() {
7272
let obj: Gd<Object> = Resource::new_gd().upcast();
7373

7474
let result = match_class!(obj, {
75-
Node(_node) => 1,
76-
Node2D(_node) => 2,
75+
_node @ Node => 1,
76+
_node @ Node2D => 2,
7777

7878
// Named fallback with access to original object.
79-
_(other) => {
79+
other @ _ => {
8080
require_object(&other);
8181
assert_eq!(other.get_class(), "Resource".into());
8282
3
@@ -90,9 +90,9 @@ fn match_class_named_fallback_matched() {
9090
fn match_class_named_fallback_unmatched() {
9191
// Test complex inline expression.
9292
let result = match_class!(Resource::new_gd().upcast::<Object>(), {
93-
Node(_node) => 1,
94-
Resource(_res) => 2,
95-
_(_ignored) => 3,
93+
_node @ Node => 1,
94+
_res @ Resource => 2,
95+
_ignored @ _ => 3,
9696
});
9797

9898
assert_eq!(result, 2);

0 commit comments

Comments
 (0)