Skip to content

Instantly share code, notes, and snippets.

@mykhailokrainik
Last active October 2, 2019 14:26
Show Gist options
  • Save mykhailokrainik/0e089d5949454b8a91ab507ac3a7b76e to your computer and use it in GitHub Desktop.
Save mykhailokrainik/0e089d5949454b8a91ab507ac3a7b76e to your computer and use it in GitHub Desktop.
State Machine in Rust implementation
//# [EN] https://hoverbear.org/2016/10/12/rust-state-machine-pattern/
//# [RU] https://habr.com/ru/post/324382/
fn main() {
// The `<StateA>` is implied here. We don't need to add type annotations!
let in_state_a = StateMachine::new("Blah blah blah".into());
// This is okay here. But later once we've changed state it won't work anymore.
in_state_a.some_unrelated_value;
println!("Starting Value: {}", in_state_a.state.start_value);
// Transition to the new state. This consumes the old state.
// Here we need type annotations (since not all StateMachines are linear in their state).
let in_state_b = StateMachine::<StateB>::from(in_state_a);
// This doesn't work! The value is moved when we transition!
// in_state_a.some_unrelated_value;
// Instead, we can use the existing value.
in_state_b.some_unrelated_value;
println!("Interm Value: {:?}", in_state_b.state.interm_value);
// And our final state.
let in_state_c = StateMachine::<StateC>::from(in_state_b);
// This doesn't work either! The state doesn't even contain this value.
// in_state_c.state.start_value;
println!("Final state: {}", in_state_c.state.final_value);
}
// Here is our pretty state machine.
struct StateMachine<S> {
some_unrelated_value: usize,
state: S,
}
// It starts, predictably, in `StateA`
impl StateMachine<StateA> {
fn new(val: String) -> Self {
StateMachine {
some_unrelated_value: 0,
state: StateA::new(val)
}
}
}
// State A starts the machine with a string.
struct StateA {
start_value: String,
}
impl StateA {
fn new(start_value: String) -> Self {
StateA {
start_value: start_value,
}
}
}
// State B goes and breaks up that String into words.
struct StateB {
interm_value: Vec<String>,
}
impl From<StateMachine<StateA>> for StateMachine<StateB> {
fn from(val: StateMachine<StateA>) -> StateMachine<StateB> {
StateMachine {
some_unrelated_value: val.some_unrelated_value,
state: StateB {
interm_value: val.state.start_value.split(" ").map(|x| x.into()).collect(),
}
}
}
}
// Finally, StateC gives us the length of the vector, or the word count.
struct StateC {
final_value: usize,
}
impl From<StateMachine<StateB>> for StateMachine<StateC> {
fn from(val: StateMachine<StateB>) -> StateMachine<StateC> {
StateMachine {
some_unrelated_value: val.some_unrelated_value,
state: StateC {
final_value: val.state.interm_value.len(),
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment