rustenumsconst-generics

enable/disable enum variant with const generic parameter


I have an enum representing various actions that can be taken. However, some of its variants only makes sense in certain contexts, known at compile-time. To limit access to certain variants, I would like to add a const generic parameter to my enum like in the code below.

enum Action<const COND1: bool, const COND2: bool> {
    A,
    B,
    C<enable if COND1>,
    D<enable if COND2>,
}

let action1 = Action<false, false>::A;
match action1 {
    Action<false, false>::A => {}
    Action<false, false>::B => {}
}

let action2 = Action<true, false>::A;
match action2 {
    Action<true, false>::A => {}
    Action<true, false>::B => {}
    Action<true, false>::C => {}
}

let action3 = Action<false, true>::A;
match action3 {
    Action<false, true>::A => {}
    Action<false, true>::B => {}
    Action<false, true>::D => {}
}

Is this possible to achieve in rust?

I could create a separate enum for each combination, but that would result in a lot of duplicated code.


Solution

  • The never type can be used to "erase" variants that use a generic type, but this usage is not yet stabilized. On nightly:

    #![feature(never_type)]
    
    enum Action<C, D> {
        A,
        B,
        C(C),
        D(D),
    }
    

    You can use the () type to enable a variant and the ! type to disable it, so Action<!, ()> would make the C variant uninhabitable; matching on such a type would therefore not require the C variant be considered.


    Until ! is stabilized for this use, you can use an uninhabitable type like Infallible (or any other empty enum) as a substitute for !. Here is one way that you could do it:

    type Enable = ();
    type Disable = std::convert::Infallible;
    
    enum Action<C, D> {
        A,
        B,
        C(C),
        D(D),
    }
    

    Now Action<Disable, Enable> has the same properties as Action<!, ()> would on nightly. Note the compiler is smart enough to figure out that the C variant is uninhabitable even without usage of ! and so, like on nightly, match does not require listing the uninhabitable variants.

    (Once ! is stabilized you can keep the same source-compatible API by changing the Disable alias to be ! instead of Infallible.)