I've found the following solution to create a macro that defines a function which returns true if an enum matches a variant:
macro_rules! is_variant {
($name: ident, $enum_type: ty, $enum_pattern: pat) => {
fn $name(value: &$enum_type) -> bool {
matches!(value, $enum_pattern)
}
}
}
Usage:
enum TestEnum {
A,
B(),
C(i32, i32),
}
is_variant!(is_a, TestEnum, TestEnum::A);
is_variant!(is_b, TestEnum, TestEnum::B());
is_variant!(is_c, TestEnum, TestEnum::C(_, _));
assert_eq!(is_a(&TestEnum::A), true);
assert_eq!(is_a(&TestEnum::B()), false);
assert_eq!(is_a(&TestEnum::C(1, 1)), false);
Is there a way to define this macro so that providing placeholders for the variant data can be avoided?
In other words, change the macro to be able to use it like so:
is_variant!(is_a, TestEnum, TestEnum::A);
is_variant!(is_a, TestEnum, TestEnum::B);
is_variant!(is_a, TestEnum, TestEnum::C);
Using std::mem::discriminant
, as described in Compare enums only by variant, not value, doesn't help since it can only be used to compare two enum instances. In this case there is only one single object and the variant identifier.
It also mentions matching on TestEnum::A(..)
but that doesn't work if the variant has no data.
You can do that using proc macros. There is a chapter in rust book that may help.
Then you can use it like:
For the above effect, proc macro crate will look like:
is_variant_derive/src/lib.rs
:Cargo.toml
for the library namedis_variant_derive
:Cargo.toml
for the binary:Then have both crates in the same directory (workspace) and then have this
Cargo.toml
:Playground
Also note that proc-macro needs to exist in its own separate crate.
Or you can directly use is_variant crate.