I am trying to use enum variants to store variables specific to tabs in an app. I am using the below code to extract the variable out of the enum. (because accessing a variant directly doesn't work, for example self.selection
doesn't work)
enum Tab {
StrokeProperties { selection: [bool; 2] },
Canvas {},
Library {},
}
let selection = match self { // `self` refers to `Tab`
Tab::StrokeProperties { selection, .. } => { selection }
_ => { !unreachable!() }
}
I want to use a macro to avoid having to write it every time. However it doesn't seem to work.
macro_rules! enum_get {
($matched_variant:expr, $matched_enum:expr, $field:ident) => {
match $matched_variant {
$matched_enum { $field, .. } => { $field },
_ => { !unreachable!() }
}
}
}
...
enum_get!(self, Tab::StrokeProperties, selection); // Ideally I would also be able to remove the reference to `Tab::StrokeProperties` entirely, but I don't understand macros well enough to do that.
--> src\ui.rs:9:27
|
9 | $matched_enum { $field, .. } => { $field },
| ^ expected one of `...`, `..=`, `..`, `=>`, `if`, or `|`
...
65 | let selection = enum_get!(self, Tab::StrokeProperties, selection);
| ------------------------------------------------- in this macro invocation
|
= note: this error originates in the macro `enum_get` (in Nightly builds, run with -Z macro-backtrace for more info)
I managed to get it working kind of, with the following code. But it isn't a nice macro, and barely cuts down on code.
macro_rules! enum_get {
($matched_variant:expr, $matched_enum:pat, $field:ident) => {
match $matched_variant {
$matched_enum => { $field },
_ => { !unreachable!() }
}
}
}
...
enum_get!(self, Tab::StrokeProperties { selection, .. }, selection);
Is it possible to make it work without the curly brackets ({ selection, .. }
) in the macro call or completely remove Tab::StrokeProperties
from the macro call?
To answer your first question, it is possible to remove the curly bracket section. It requires matching the enum variant (Tab::StrokeProperties
) as a path
not an expr
or complete pat
tern. Documentation of available macro_rules!
argument types can be found here. Here is the working code:
enum Tab {
StrokeProperties { selection: [bool; 2] },
Canvas {},
Library {},
}
macro_rules! enum_get {
($matched_variant:expr, $matched_enum:path, $field:ident) => {
match $matched_variant {
$matched_enum { $field, .. }=> { $field },
_ => { unreachable!() }
}
}
}
fn main() {
let tab = Tab::StrokeProperties{selection: [false; 2]};
let selection = enum_get!(tab, Tab::StrokeProperties, selection);
println!("{selection:?}"); // [false, false]
}
To answer your second question, it is not possible to remove Tab::StrokeProperties
entirely, because the macro has no way of knowing which enum variants/fields exist, unless you made a more complex macro that consumed the entire enum Tab { ... }
item.