Skip to content

Instantly share code, notes, and snippets.

@a-voronov
Last active October 12, 2019 20:06
Show Gist options
  • Save a-voronov/22276c89e97f61d43e4777800bc747b2 to your computer and use it in GitHub Desktop.
Save a-voronov/22276c89e97f61d43e4777800bc747b2 to your computer and use it in GitHub Desktop.
Type-Safe FSM with Phantom Types 👻
// inspired by https://blog.jle.im/entry/introduction-to-singletons-1.html
protocol DoorState {}
enum Opened: DoorState {}
enum Closed: DoorState {}
enum Locked: DoorState {}
struct Door<State: DoorState> {
let id: Int
}
extension Door where State == Closed {
func open() -> Door<Opened> { .init(id: id) }
func lock() -> Door<Locked> { .init(id: id) }
func forceLock() -> Door<Locked> { lock() }
}
extension Door where State == Opened {
func close() -> Door<Closed> { .init(id: id) }
func forceLock() -> Door<Locked> { close().lock() }
}
extension Door where State == Locked {
func unlock() -> Door<Closed> { .init(id: id) }
func forceLock() -> Door<Locked> { self }
}
Door<Closed>(id: 0)
.open() // Door<Opened>
.close() // Door<Closed>
.lock() // Door<Locked>
.unlock() // Door<Closed>
Door<Opened>(id: 1).forceLock() // Door<Locked>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment