Skip to content

Instantly share code, notes, and snippets.

@erikhuizinga
Last active March 1, 2021 14:02
Show Gist options
  • Save erikhuizinga/05a2712bdb0f32c45fa192cd137770e0 to your computer and use it in GitHub Desktop.
Save erikhuizinga/05a2712bdb0f32c45fa192cd137770e0 to your computer and use it in GitHub Desktop.
UniFlow out of order state publishing
// Run with:
// kotlinc -script script.main.kts
@file:Repository("https://jcenter.bintray.com")
@file:DependsOn("io.uniflow:uniflow-core:0.11.6")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5")
import io.uniflow.core.flow.*
import io.uniflow.core.flow.data.UIEvent
import io.uniflow.core.flow.data.UIState
import kotlinx.coroutines.*
import java.util.concurrent.Executors
import kotlin.reflect.KClass
import kotlin.system.exitProcess
// Simulate single 'main' thread
val coroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
val coroutineScope = CoroutineScope(coroutineDispatcher)
data class State(val value: Int) : UIState()
val defaultValue = 0
val increment = 1
var lastValue = defaultValue
// This script cancels itself after a while
coroutineScope.launch {
delay(100)
coroutineScope.cancel()
}
val uiDataPublisher = object : UIDataPublisher {
override suspend fun publishState(state: UIState) = withContext(coroutineDispatcher) {
// Publish state on single 'main' thread
// Optionally print thread name
// println("${Thread.currentThread()} = publishState thread")
require(state is State)
val value = state.value
val lastValueCopy = lastValue
val expectedValue = lastValueCopy + increment
// Require that values are observed in order
// Disable this to see values printed to console, many of which are published out of order!
if (value != expectedValue) {
System.err.println("value = $value but expected value = $expectedValue after $lastValueCopy")
}
lastValue = value
}
override suspend fun publishEvent(event: UIEvent) {
TODO("not implemented")
}
}
val uiDataStore = UIDataStore(
publisher = uiDataPublisher,
defaultState = State(defaultValue),
tag = "UIDataStore 1337"
)
val actionReducer = ActionReducer(
uiDataStore = uiDataStore,
coroutineScope = coroutineScope,
defaultDispatcher = Dispatchers.IO /* This is the default in AndroidDataFlow */,
tag = "ActionReducer 1337"
)
val dataFlow = object : DataFlow {
private val actionDispatcher = ActionDispatcher(
coroutineScope = coroutineScope,
reducer = actionReducer,
dataStore = uiDataStore,
dataFlow = this,
tag = "ActionDispatcher 1337"
)
override fun action(onAction: suspend ActionFlow.(UIState) -> Unit): ActionFlow =
actionDispatcher.action(onAction)
override fun action(
onAction: suspend ActionFlow.(UIState) -> Unit,
onError: suspend ActionFlow.(Exception, UIState) -> Unit
): ActionFlow {
TODO("not implemented")
}
override fun <T : UIState> actionOn(
stateClass: KClass<T>,
onAction: suspend ActionFlow.(T) -> Unit
): ActionFlow {
TODO("not implemented")
}
override fun <T : UIState> actionOn(
stateClass: KClass<T>,
onAction: suspend ActionFlow.(T) -> Unit,
onError: suspend ActionFlow.(Exception, UIState) -> Unit
): ActionFlow {
TODO("not implemented")
}
override fun getCurrentState(): UIState {
TODO("not implemented")
}
override fun <T : UIState> getCurrentStateOrNull(stateClass: KClass<T>): T? {
TODO("not implemented")
}
}
var currentValue = defaultValue
// Generate a lot of actions
while (coroutineScope.isActive) {
currentValue += increment
val nextValue = currentValue
dataFlow.action {
setState {
// Optionally print thread name
// println("${Thread.currentThread()} = setState thread")
// Set the state to the next value
State(nextValue)
}
}
}
exitProcess(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment