Created
April 18, 2025 18:01
-
-
Save kayvank/aad6fcfc78b741276cfb76cb2b907362 to your computer and use it in GitHub Desktop.
Type driven State Machine in Rust, using nix script
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
| #!/usr/bin/env nix-shell | |
| //! ```cargo | |
| //! [dependencies] | |
| //! time = "0.1.25" | |
| //! ``` | |
| /* | |
| #!nix-shell -i rust-script -p rustc -p rust-script -p cargo | |
| */ | |
| #[derive(Debug, Clone, Copy)] | |
| struct BottleFillingMachineConfig { | |
| waiting_time: std::time::Duration, | |
| filling_rate: usize, | |
| } | |
| #[derive(Debug)] | |
| struct BottleFillingMachine<S> { | |
| config: BottleFillingMachineConfig, | |
| state: S, | |
| } | |
| // some states | |
| #[derive(Debug)] | |
| struct Waiting { | |
| waiting_time: std::time::Duration, | |
| } | |
| #[derive(Debug)] | |
| struct Filling { | |
| filling_rate: usize, | |
| is_full: bool, | |
| } | |
| #[derive(Debug)] | |
| struct Done; | |
| #[derive(Debug)] | |
| struct BottleIsNotFull; | |
| #[derive(Debug)] | |
| struct BottleIsFull; | |
| // we leave these here, in case we need to carry state when we're done | |
| enum BottleInMachineStatus { | |
| NotFull(BottleIsNotFull), | |
| Full(BottleIsFull), | |
| } | |
| // the machine starts @waiting states | |
| impl BottleFillingMachine<Waiting> { | |
| fn new(config: BottleFillingMachineConfig) -> Self { | |
| let waiting_time: std::time::Duration = config.waiting_time; | |
| BottleFillingMachine { | |
| config, | |
| state: Waiting { waiting_time }, | |
| } | |
| } | |
| } | |
| impl BottleFillingMachine<Filling> { | |
| // TODO make this async and alternate states | |
| fn bottle_status_dettector(&self) -> BottleInMachineStatus { | |
| if self.config.filling_rate > 0 { | |
| BottleInMachineStatus::Full(BottleIsFull) | |
| } else { | |
| BottleInMachineStatus::NotFull(BottleIsNotFull) | |
| } | |
| } | |
| } | |
| impl From<BottleFillingMachine<Done>> for BottleFillingMachine<Waiting> { | |
| fn from(machine: BottleFillingMachine<Done>) -> Self { | |
| BottleFillingMachine { | |
| config: machine.config, | |
| state: Waiting {waiting_time: machine.config.waiting_time}, | |
| } | |
| } | |
| } | |
| impl From<BottleFillingMachine<Waiting>> for BottleFillingMachine<Filling> { | |
| fn from(machine: BottleFillingMachine<Waiting>) -> Self { | |
| BottleFillingMachine { | |
| config: machine.config, | |
| state: Filling { | |
| filling_rate: machine.config.filling_rate, | |
| is_full: false, | |
| }, | |
| } | |
| } | |
| } | |
| impl TryFrom<BottleFillingMachine<Filling>> for BottleFillingMachine<Done> { | |
| type Error = BottleIsNotFull; | |
| fn try_from(machine: BottleFillingMachine<Filling>) -> Result<Self, Self::Error> { | |
| match machine.bottle_status_dettector() { | |
| BottleInMachineStatus::Full(BottleIsFull) => Ok(BottleFillingMachine { | |
| config: machine.config, | |
| state: Done, | |
| }), | |
| BottleInMachineStatus::NotFull(BottleIsNotFull) => Err(BottleIsNotFull), | |
| } | |
| } | |
| } | |
| // transitions between states | |
| fn main() { | |
| let config = BottleFillingMachineConfig { | |
| waiting_time: std::time::Duration::new(10, 10), | |
| filling_rate: 10usize, | |
| }; | |
| let machine: BottleFillingMachine<Waiting> = BottleFillingMachine::new(config); | |
| println!("machine initial state : {:?}", machine); | |
| let filling_machine: BottleFillingMachine<Filling> = machine.into(); | |
| println!("machine filling state : {:?}", filling_machine); | |
| let done_machine: Result<BottleFillingMachine<Done>, BottleIsNotFull> = | |
| filling_machine.try_into(); | |
| let back_waiting_machine: Option<BottleFillingMachine<Waiting>> = | |
| match done_machine { | |
| Ok(d) => { | |
| println!("machine done state : {:?}", d); | |
| let machine: BottleFillingMachine<Waiting> = d.into(); | |
| Some(machine) | |
| }, | |
| e => { | |
| println!("machine not done state : {:?}", e); | |
| None | |
| }, | |
| }; | |
| println!("optional reset state: {:?}", back_waiting_machine); | |
| println!("hello rust script"); | |
| } | |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Prerequisit
How to use it
factory_bottle.rsand copy/paste the code in it