Closed
Description
The problem of encoding some sort of state machine is common for many programs, such as building parsers, schedulers, protocols, or coroutines. This proposal extends enums to allow them to express state machines.
Enums would be extended with extra syntax as follows. The design is intended not to break any existing code. Enums would retain all of the features they currently have, but they would also have extra abilities. For example
pub enum MyStates {
// The `=> State2` denotes that an enum with value `State1` can only
// have its value changed to `State2`.
State1(u32) => State2,
// A variant can have multiple successor states
State2 => {State3, State4},
State3(IpAddr) => {State4, Error},
// A variant can decide to transition to itself, which means that once
// the state machine gets into state `Error`, it is stuck there.
Error => Error,
// A variant without explicit next states implicitly can transition to any
// other variant/state. This makes sure that current code does not break.
State4,
}
I think it should be relatively easy to enforce these constraints in safe code statically with little or no non-local reasoning. (Not 100% sure about this, though... Can someone find a counterexample?). For example,
pub fn advance_fsm(fsm: &mut MyState) {
match fsm {
&mut MyState::State1(i) => {
send_msg(i);
// This assignment can ONLY be to `State2`
*fsm = MyState::State2;
}
&mut MyState::State2 => {
// COMPILE ERROR: Illegal state transition: State2 -> State1
*fsm = MyState::State1;
}
&mut MyState::State3(ip) => if connect(ip) {
*fsm = MyState::State4;
} else {
*fsm = MyState::Error;
},
&mut MyState::State4 => *fsm = MyState::State1,
&mut MyState::Error => {}
}
}