Last active
August 20, 2024 14:30
-
-
Save Ortham/e8942d622d91e2e87a3c5b7f6545d745 to your computer and use it in GitHub Desktop.
Example of typestates in Rust using generics
This file contains 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
trait DoorState {} | |
// PhantomData is a zero-sized type that tells the compiler to pretend that | |
// Door actually stores a value of type State, since otherwise we'd get an | |
// unused type parameter error. | |
struct Door<State: DoorState> { number: u8, state: std::marker::PhantomData<State> } | |
// Our states don't actually hold any data. If they did, we wouldn't need | |
// PhantomData. | |
struct Open {} | |
struct Closed {} | |
struct Locked {} | |
impl DoorState for Open {} | |
impl DoorState for Closed {} | |
impl DoorState for Locked {} | |
impl<T: DoorState> Door<T> { | |
fn new(number: u8) -> Door<T> { | |
Door { number, state: std::marker::PhantomData } | |
} | |
fn number(&self) -> u8 { | |
self.number | |
} | |
} | |
impl Door<Open> { | |
fn close(self) -> Door<Closed> { | |
Door::new(self.number) | |
} | |
} | |
impl Door<Closed> { | |
fn open(self) -> Door<Open> { | |
Door::new(self.number) | |
} | |
fn lock(self) -> Door<Locked> { | |
Door::new(self.number) | |
} | |
} | |
impl Door<Locked> { | |
fn unlock(self) -> Door<Closed> { | |
Door::new(self.number) | |
} | |
} | |
fn main() { | |
let closed_door = Door::<Closed>::new(1); | |
println!("Closed door number is {}", closed_door.number()); | |
// We can open a closed door. | |
let opened_door = closed_door.open(); | |
println!("Open door number is {}", opened_door.number()); | |
// We can't open a closed door twice though. | |
// closed_door.open(); | |
// We also can't close a door that is already closed. | |
// closed_door.close(); | |
// Now that the door is opened, we can close it. | |
let closed_door = opened_door.close(); | |
println!("Closed door number is {}", closed_door.number()); | |
// A closed door can be locked. | |
let locked_door = closed_door.lock(); | |
println!("Locked door number is {}", locked_door.number()); | |
// A locked door can be unlocked. | |
let unlocked_door = locked_door.unlock(); | |
println!("Unlocked door number is {}", unlocked_door.number()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment