Enum_dispatch with a generic trait

I want to propagate a generic trait methods to a enum wrapper like this:

trait State<T>: Sized {
    fn next(self) -> T;
}

enum Machine {
    One(One),
}
impl From<One> for Machine {
    fn from(src: One) -> Self {
        Self::One(src)
    }
}
impl State<Machine> for Machine {
    fn next(self) -> Self {
        match self {
            Self::One(state) => state.next(),
        }
    }
}

struct One;
impl State<Machine> for One {
    fn next(self) -> Machine {
        self.into()
    }
}

fn main() {
    let m = Machine::One(One);
    m.next();
}

But I can't figure out how to express this with enum_dispatch. This won't compile and cargo expand says enum_dispatch doesn't do anything:

use enum_dispatch::enum_dispatch;

#[enum_dispatch]
trait State<T>: Sized {
    fn next(self) -> T;
}

#[enum_dispatch(State)]
enum Machine {
    One(One),
}

struct One;
impl State<Machine> for One {
    fn next(self) -> Machine {
        self.into()  // the trait `From<One>` is not implemented for `Machine`
    }
}

fn main() {
    let m = Machine::One(One);
    m.next();  // method not found in `Machine`
}

To make this work, you need to change the attribute on the enum to #[enum_dispatch(State<Machine>)], and you need to rename State's generic parameter to be Machine. This is pretty hacky though; I'm not sure this is inteded use of the enum_dispatch macro. But it works.

Working code:

use enum_dispatch::enum_dispatch;

#[enum_dispatch]
trait State<Machine>: Sized {
    fn next(self) -> Machine;
}

#[enum_dispatch(State<Machine>)]
enum Machine {
    One(One),
}

struct One;
impl State<Machine> for One {
    fn next(self) -> Machine {
        self.into()
    }
}

fn main() {
    let m = Machine::One(One);
    m.next();
}
1 Like

Possibly relevant:

1 Like

Thanks a lot, that's exactly what I was looking for :slight_smile:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.