Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 869
Fredrik Enetorp Avatar asked Sep 18 '25 22:09

Fredrik Enetorp


1 Answers

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.)

like image 120
cdhowie Avatar answered Sep 20 '25 12:09

cdhowie