Created
April 30, 2025 21:30
-
-
Save noncombatant/f91d5d049661bd7ae009053c862fdf0b to your computer and use it in GitHub Desktop.
Statically checked state machine with traits
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
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