Skip to content

Instantly share code, notes, and snippets.

@Bill
Last active July 31, 2019 15:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Bill/d5fa8c0290e49fccb90936745b29e86f to your computer and use it in GitHub Desktop.
Save Bill/d5fa8c0290e49fccb90936745b29e86f to your computer and use it in GitHub Desktop.
Kotlin turnstile state machine using a sealed class
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.produce
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.selects.select
sealed class State {
/**
* Process the first input from the channel(s) [perform a side-effect] and return a new functional.State
*/
abstract suspend fun process(
pushes: ReceiveChannel<Unit>,
coins: ReceiveChannel<Unit>): State
}
private object locked : State() {
override suspend fun process(pushes: ReceiveChannel<Unit>, coins: ReceiveChannel<Unit>): State {
return select<State> {
pushes.onReceive {
println("push blocked---turnstile is functional.locked")
locked
}
coins.onReceive {
println("coins received---unlocking")
unlocked
}
}
}
}
private object unlocked : State() {
override suspend fun process(pushes: ReceiveChannel<Unit>, coins: ReceiveChannel<Unit>): State {
return select<State> {
pushes.onReceive {
println("Opened!")
locked
}
coins.onReceive {
println("Already functional.unlocked---returning coins")
unlocked
}
}
}
}
private fun CoroutineScope.turnstile(
pushes: ReceiveChannel<Unit>,
coins: ReceiveChannel<Unit>) = launch {
var state: State = locked
while(true) {
state = state.process(pushes,coins)
}
}
fun main() = runBlocking<Unit> {
val pushes = produce {
repeat(10) {
send(Unit)
}
}
val coins = produce {
repeat(10) {
send(Unit)
}
}
turnstile(pushes,coins)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment