It's possible to create an is_of
function like you suggest, but with some caveats, and I don't recommend it.
In general, you can indeed pass enum variants as function parameters. While enum variants are not types, they are functions, and you can pass functions as parameters all you want. The problem is making an is_of
function that can take any of your variants as an argument.
If all of your variants took the same type, you could do this:
#[derive(Clone, Copy, PartialEq)]
enum Foo {
A(u64),
B(u64),
C(u64),
}
impl Foo {
fn into_inner(self) -> u64 {
match self {
Foo::A(n) | Foo::B(n) | Foo::C(n) => n
}
}
fn is_of(self, variant: fn(u64) -> Foo) -> bool {
self == variant(self.into_inner())
}
}
fn main() {
assert!(Foo::A(10).is_of(Foo::A))
}
Importantly, is_of
will take any function pointer that returns Foo
, so you can pass in arbitrary functions with the correct signature in addition to the variants.
Alternatively, if all your variants are different types (as in your case), you can define a trait that will allow you to pass the different variants in.
enum Bar {
A(u64),
B(u32, i32),
}
impl Bar {
fn is_of<V: Variant<Args>, Args>(self, variant: V) -> bool {
V::check(self)
}
}
trait Variant<Args> {
fn check(this: Bar) -> bool;
}
impl<F: Fn(u64) -> Bar> Variant<(u64,)> for F {
fn check(this: Bar) -> bool {
matches!(this, Bar::A(_))
}
}
impl<F: Fn(u32, i32) -> Bar> Variant<(u32, i32)> for F {
fn check(this: Bar) -> bool {
matches!(this, Bar::B(_, _))
}
}
Obviously, this code is not really doing anything useful, and it opens you up to all sorts of bugs. If you were gonna do something like this, you would probably want to generate the trait definitions with a macro at least. And it has the same caveat as above that it'll accept any functions with matching signatures, not just the variants.
Playground link
matches!(a, D::A(_))
– Holding