Created
April 7, 2024 06:49
-
-
Save matthewjberger/2bae1083169d0362dc7c1fdd5e61ba4d to your computer and use it in GitHub Desktop.
rust state machines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//#![no_std] | |
use serde::{Deserialize, Serialize}; | |
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)] | |
pub enum State { | |
State1, | |
State2, | |
State3, | |
} | |
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)] | |
pub enum Event { | |
Event1, | |
Event2, | |
Event3, | |
} | |
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)] | |
pub enum Guard { | |
CountLessThan(u32), | |
None, | |
} | |
#[derive(Debug, Serialize, Deserialize)] | |
pub struct Transition { | |
pub from: State, | |
pub on: Event, | |
pub to: State, | |
pub guard: Guard, | |
} | |
#[derive(Debug, Serialize, Deserialize)] | |
pub struct StateMachine { | |
pub state: State, | |
pub transitions: Vec<Transition>, | |
pub data: Data, | |
} | |
#[derive(Debug, Serialize, Deserialize, Default)] | |
pub struct Data { | |
pub count: u32, | |
} | |
impl StateMachine { | |
pub fn new() -> Self { | |
Self { | |
state: State::State1, | |
transitions: vec![ | |
Transition { | |
from: State::State1, | |
on: Event::Event1, | |
to: State::State1, | |
guard: Guard::None, | |
}, | |
Transition { | |
from: State::State1, | |
on: Event::Event2, | |
to: State::State2, | |
guard: Guard::CountLessThan(3), | |
}, | |
Transition { | |
from: State::State2, | |
on: Event::Event1, | |
to: State::State1, | |
guard: Guard::None, | |
}, | |
Transition { | |
from: State::State2, | |
on: Event::Event3, | |
to: State::State3, | |
guard: Guard::None, | |
}, | |
], | |
data: Data::default(), | |
} | |
} | |
pub fn process_event(&mut self, event: Event) { | |
let next_state = self | |
.transitions | |
.iter() | |
.find(|t| t.from == self.state && t.on == event && evaluate_guard(&t.guard, &self.data)) | |
.map(|t| t.to) | |
.or_else(|| Some(self.state)); | |
self.transition(next_state.unwrap()); | |
} | |
fn transition(&mut self, next_state: State) { | |
let current_state = std::mem::replace(&mut self.state, next_state); | |
handle_state_exit(current_state, &mut self.data); | |
handle_state_enter(self.state, &mut self.data); | |
} | |
} | |
fn evaluate_guard(guard: &Guard, data: &Data) -> bool { | |
match guard { | |
Guard::CountLessThan(threshold) => data.count < *threshold, | |
Guard::None => true, | |
} | |
} | |
fn handle_state_enter(state: State, data: &mut Data) { | |
match state { | |
State::State1 => { | |
println!("Entered State1"); | |
data.count += 1; | |
} | |
State::State2 => { | |
println!("Entered State2"); | |
} | |
State::State3 => { | |
println!("Entered State3"); | |
data.count = 0; | |
} | |
} | |
} | |
fn handle_state_exit(_state: State, _data: &mut Data) { | |
// Handle state exit actions if needed | |
} | |
fn main() { | |
let mut sm = StateMachine::new(); | |
sm.process_event(Event::Event1); // Stay in State1 | |
sm.process_event(Event::Event2); // Transition to State2 | |
sm.process_event(Event::Event1); // Transition to State1 | |
sm.process_event(Event::Event2); // Transition to State2 | |
sm.process_event(Event::Event2); // Stay in State2 | |
sm.process_event(Event::Event3); // Transition to State3 | |
sm.process_event(Event::Event1); // Transition to State1 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment