Skip to content

Instantly share code, notes, and snippets.

@noncombatant
Created April 30, 2025 21:30
Show Gist options
  • Save noncombatant/f91d5d049661bd7ae009053c862fdf0b to your computer and use it in GitHub Desktop.
Save noncombatant/f91d5d049661bd7ae009053c862fdf0b to your computer and use it in GitHub Desktop.
Statically checked state machine with traits
mod stateless_sequencer {
pub trait Cold {
fn turn_on(self) -> impl Warm;
}
pub trait Warm {
fn suspend(self) -> impl Suspended;
fn turn_off(self) -> impl Cold;
}
pub trait Suspended {
fn wake_up(self) -> impl Warm;
fn turn_off(self) -> impl Cold;
}
struct Sequencer;
impl Cold for Sequencer {
fn turn_on(self) -> impl Warm {
println!("Cold::turn_on");
self
}
}
impl Warm for Sequencer {
fn suspend(self) -> impl Suspended {
println!("Warm::suspend");
self
}
fn turn_off(self) -> impl Cold {
println!("Warm::turn_off");
self
}
}
impl Suspended for Sequencer {
fn wake_up(self) -> impl Warm {
println!("Suspended::wake_up");
self
}
fn turn_off(self) -> impl Cold {
println!("Suspended::turn_off");
self
}
}
pub fn initialize_system() -> impl Cold {
Sequencer
}
pub fn demo() {
let sequencer = initialize_system();
let sequencer = sequencer.turn_on();
// This won't compile, because `sequencer` is-a `Warm`, which has no
// `turn_on`.
//
// let sequencer = sequencer.turn_on();
let sequencer = sequencer.suspend();
let sequencer = sequencer.turn_off();
let sequencer = sequencer.turn_on();
let sequencer = sequencer.suspend();
let sequencer = sequencer.wake_up();
let _ = sequencer.turn_off();
}
}
mod stateful_sequencer {
pub trait Cold {
fn turn_on(&mut self) -> &mut dyn Warm;
fn print_status(&self);
}
pub trait Warm {
fn suspend(&mut self) -> &mut dyn Suspended;
fn turn_off(&mut self) -> &mut dyn Cold;
fn print_status(&self);
}
pub trait Suspended {
fn wake_up(&mut self) -> &mut dyn Warm;
fn turn_off(&mut self) -> &mut dyn Cold;
fn print_status(&self);
}
struct Sequencer {
status: &'static str,
}
impl Sequencer {
fn print_status(&self) {
println!("{}", self.status);
}
}
impl Cold for Sequencer {
fn turn_on(&mut self) -> &mut dyn Warm {
self.status = "Cold::turn_on";
self
}
fn print_status(&self) {
self.print_status();
}
}
impl Warm for Sequencer {
fn suspend(&mut self) -> &mut dyn Suspended {
self.status = "Warm::suspend";
self
}
fn turn_off(&mut self) -> &mut dyn Cold {
self.status = "Warm::turn_off";
self
}
fn print_status(&self) {
self.print_status();
}
}
impl Suspended for Sequencer {
fn wake_up(&mut self) -> &mut dyn Warm {
self.status = "Suspended::wake_up";
self
}
fn turn_off(&mut self) -> &mut dyn Cold {
self.status = "Suspended::turn_off";
self
}
fn print_status(&self) {
self.print_status();
}
}
pub fn initialize_system() -> impl Cold {
Sequencer {
status: "initialized",
}
}
pub fn demo() {
let mut sequencer = initialize_system();
sequencer.print_status();
let sequencer = sequencer.turn_on();
sequencer.print_status();
// This won't compile, because `sequencer` is-a `Warm`, which has no
// `turn_on`.
//
// let sequencer = sequencer.turn_on();
let sequencer = sequencer.suspend();
sequencer.print_status();
let sequencer = sequencer.turn_off();
sequencer.print_status();
let sequencer = sequencer.turn_on();
sequencer.print_status();
let sequencer = sequencer.suspend();
sequencer.print_status();
let sequencer = sequencer.wake_up();
sequencer.print_status();
let sequencer = sequencer.turn_off();
sequencer.print_status();
}
}
fn main() {
{
use stateless_sequencer::demo;
println!("Stateless");
demo();
}
{
use stateful_sequencer::demo;
println!("Stateful");
demo();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment