Get enum discriminant without constructing an instance

Viewed 1217

I need to store a vector of enum discriminants to compare against:

use std::mem;

enum Thing {
    Foo(usize),
    Bar(usize, usize),
}

let ds: Vec<mem::Discriminant<Thing>> = vec![/* ??? */];

// ...

let thing: Thing = Foo(1234);

for d in ds.iter() {
    if mem::discriminant(thing) == d {
        println!("yay");
    }
}

In practice, what will happen is a macro will be used to generate this list of discriminants in order to match context in a list of enums.

For example, we might have something that looks like this:

enum Thing {
    A(usize),
    B(f32),
    C(u8, u8, u8),
}

context_rule! {
    A(a) B(b) C(c) B(d) : a + b + c < d => C(b * c)
}

Which should generate a vector of the discriminants corresponding to vec![A, B, C, B] to be checked against.

1 Answers

I don't think this functionality exists. Looking at the RFCs (1 2) for the discriminant API, it was designed for a fairly small use-case.

When using an ADT enum that contains data in some of the variants, it is sometimes desirable to know the variant but ignore the data, in order to compare two values by variant or store variants in a hash map when the data is either unhashable or unimportant.

With that and your intended use-case in mind, I would suggest another route. If you want to have a vector of things, see if the elements match a pattern, and do something with the data; you can simply use a match with a slice pattern.

enum Thing {
    A(usize),
    B(usize),
    C(usize, usize, usize),
}

fn main() {
    use Thing::*;

    let things = vec![A(0), B(1), C(2, 3, 4), B(5)];
    let result = match things.as_slice() {
        &[A(a), B(b), C(c, _, _), B(d)] if a + b + c < d => {
            C(b * c, 0, 0)
        }
        _ => todo!("add fallback")
    };

    // do something with result
}

The match arm looks very similar to your proposed macro.

Related