Skip to content

Instantly share code, notes, and snippets.

@matthewjberger
Created April 7, 2024 06:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewjberger/2bae1083169d0362dc7c1fdd5e61ba4d to your computer and use it in GitHub Desktop.
Save matthewjberger/2bae1083169d0362dc7c1fdd5e61ba4d to your computer and use it in GitHub Desktop.
rust state machines
//#![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