templatesrustenumstransmute

Rust : Cast a Enum to itself with Generics Specialization


I'm using generics specialization to have custom compile time type on some enum data structure :

pub trait MyEnumState{}

// All state are Zero Sized Type
pub struct State1; impl MyEnumState for State1{};
pub struct State2; impl MyEnumState for State2{};

// Note : I don't know is there is a PhantomData<S> for an enum
pub enum MyEnum<S: MyEnumState> {
    A,
    B,
    C(i32), // Can also have some data
    // ... long enum
}

Now I would like to be able to cast them around : same value, different type

// How to avoid this mess ???
impl MyEnum<State1> {
    pub fn to_state2(self) -> MyEnum<State2> {
        match self {
            MyEnum::A => MyEnum::A,
            MyEnum::B => MyEnum::B,
            MyEnum::C(v) => MyEnum::C(v),
        }
    }
}

// I can proably make a generic function
// ```
// fn cast
//     <StateBegin : MyEnumState, StateEnd : MyEnumState>
// (val MyEnum<StateBegin>) -> MyEnum<StateEnd> { ... }
// ```
// to avoid repetition but I still have at least 1 giant match to implement
impl MyEnum<State2> { ... }



impl<S : MyEnumState> MyEnum<S> 
{
   pub fn to_state<NewState : MyEnumState>(self) ->  MyEnum<NewState> 
   {
      // how ?!
   }
}

This is just a simple example, the goal is to have 0 match statements to avoid matching for all existing enum variant.


Solution

  • One way is to put the PhantomData field outside of the enum in a wrapper struct:

    use core::marker::PhantomData;
    
    pub enum MyEnum {
        A,
        B,
        C(i32),
    }
    
    pub struct EnumWithState<S: MyEnumState> {
        data: MyEnum,
        _state: PhantomData<S>,
    }
    

    Then you can implement the type casting function on EnumWithState:

    impl<S: MyEnumState> EnumWithState<S> {
        fn to_state<S2: MyEnumState>(self) -> EnumWithState<S2> {
            EnumWithState {
                data: self.data,
                _state: PhantomData,
            }
        }
    }