How to implement TypeState instead of enums for

⚓ Rust    📅 2026-06-17    👤 surdeus    👁️ 4      

surdeus

Hey all,
How can you implement the typestate pattern with generic types instead of an enum for a linked list?
Would this have any performance impact?

Here is some minimal example:

    enum EnumVariant {
        A,
        B,
    }
    impl EnumVariant {
        /// abstract example for the function that changes the Enum Variant
        pub fn change(&mut self) {
            if let EnumVariant::A = self {
                *self = EnumVariant::B
            }
        }
        /// abstract example for functions that depend on the Enum
        pub fn do_something(&self) {
            match self {
                Self::A => println!("a"),
                Self::B => println!("b"),
            }
        }
        pub fn do_something_for_a(&self) {
            if let Self::A = self {
                println!("a only")
            }
        }
    }

    /// master struct that owns many of these enums
    struct MasterStructEnumVariant {
        vec: Vec<EnumVariant>,
    }
    impl MasterStructEnumVariant {
        pub fn change(&mut self) {
            self.vec.iter_mut().for_each(|e| e.change());
        }
    }

For the real example the do_something* functions all boilerplate code.. The MasterStructEnumVariant contains a vector of these enums and in the real example, EnumVariant::B will again contain a vector to other MasterStructEnumVariant.

How would it be possible to change this to a typestate pattern?
this would directly eliminate the boilerplate code for those individual functions...

    struct StructA;
    struct StructB;
    struct TypeStateVariant<T> {
        val: T,
    }
    impl TypeStateVariant<StructA> {
        pub fn change(&mut self) {
            // how to correctly specify the types?
            *self = StructB;
        }
    }

    struct MasterStructTypeStateVariant<T> {
        vec: Vec<TypeStateVariant<T>>,
    }
    impl MasterStructTypeStateVariant<StructA> {
        pub fn change(&mut self) {
            // this is also changing the generic type of MasterStructTypeStateVariant
            self.vec.iter_mut().for_each(|e| e.change());
        }
        // function definitions become easier :-)
        pub fn do_something(&self) {
            println!("a")
        }
        // this becomes easily possible :-)
        pub fn do_something_for_a(&self) {
            println!("a only")
        }
    }
    impl MasterStructTypeStateVariant<StructB> {
        pub fn do_something(&self) {
            println!("b")
        }
    }

but this is raising

error[E0308]: mismatched types
  --> src\mastermind\mastermind_solver.rs:50:21
   |
50 |             *self = StructB;
   |             -----   ^^^^^^^ expected `TypeStateVariant<StructA>`, found `StructB`
   |             |
   |             expected due to the type of this binding
   |
   = note: expected struct `TypeStateVariant<StructA>`
              found struct `StructB`

It would be possible to do something like

impl TypeStateVariant<StructA> {
        pub fn change(mut self) -> TypeStateVariant<StructB> {
            // how to correctly specify the types?
            TypeStateVariant { val: StructB }
        }
    }
impl MasterStructTypeStateVariant<StructA> {
        pub fn change(&mut self) {
            self.vec = self.vec.drain().map(|e| e.change());
        }
}

which is just shifting this issue one level up.

error[E0308]: mismatched types
  --> src\mastermind\mastermind_solver.rs:65:24
   |
65 |             self.vec = self.vec.drain().map(|e| e.change());
   |             --------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Vec<TypeStateVariant<StructA>>`, found `Map<Drain<'_, ...>, ...>`
   |             |
   |             expected due to the type of this binding
   |
   = note: expected struct `Vec<TypeStateVariant<StructA>>`
              found struct `std::iter::Map<std::vec::Drain<'_, TypeStateVariant<StructA>>, {closure@src\mastermind\mastermind_solver.rs:65:45: 65:48}>`

Is there a better way than creating a function that consumes MasterStructTypeStateVariant and re-creates one with the other type?
...that would totally blow up my use case and not bring any benefit over the enums...

2 posts - 2 participants

Read full topic

🏷️ Rust_feed