Skip to content

Instantly share code, notes, and snippets.

@Ortham
Last active September 15, 2023 13:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ortham/e8942d622d91e2e87a3c5b7f6545d745 to your computer and use it in GitHub Desktop.
Save Ortham/e8942d622d91e2e87a3c5b7f6545d745 to your computer and use it in GitHub Desktop.
Example of typestates in Rust using generics
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