martmists
12/11/2023, 2:18 PMflow.singleOrNull()
always returns null, whereas flow.collect { println(it) }
does print the expected result. Why does this happen?Joffrey
12/11/2023, 2:19 PMSam
12/11/2023, 2:19 PMmartmists
12/11/2023, 2:20 PMmartmists
12/11/2023, 2:21 PMSam
12/11/2023, 2:22 PMproduceIn
.Sam
12/11/2023, 2:24 PMsingleOrNull
you'll see that it returns null if there are no elements or if more than one element is found.martmists
12/11/2023, 2:27 PMSam
12/11/2023, 2:28 PMSam
12/11/2023, 2:30 PMmartmists
12/11/2023, 2:33 PMcontext(SequenceScope<T>)
), so I switched to Flows instead which did not have this limitation, but were more confusing to useSam
12/11/2023, 2:34 PMmartmists
12/11/2023, 2:37 PMSam
12/11/2023, 2:38 PMkotlinx.coroutines
to use the sequence { ... }
generator.Sam
12/11/2023, 2:39 PM@RestrictsSuspension
-- I would expect that to be fixed before a proper release.Sam
12/11/2023, 2:42 PMsuspendCoroutine
is that it's designed to be compatible with many different paradigms, not just kotlinx.coroutines
! Could be a fun project to dig into how the sequence builder is implemented in the stdlib and copy the basic idea to make your own generators.martmists
12/11/2023, 7:27 PMprivate class LuaCoroutineScopeImpl : LuaCoroutineScope, LuaCoroutineCommunication, Continuation<Unit> {
enum class State {
READY, SUSPENDED, DEAD, FAILED
}
private var state = State.READY
private var nextValue: LuaStatus? = null
var nextStep: Continuation<List<TValue<*>>>? = null
override fun send(values: List<TValue<*>>): LuaStatus {
if (hasNext(values)) {
return next()
} else {
throw IllegalStateException("No next value")
}
}
private fun hasNext(values: List<TValue<*>>): Boolean {
while (true) {
when (state) {
State.READY, State.SUSPENDED -> {
val step = nextStep ?: throw IllegalStateException("No next step")
nextStep = null
step.resume(values)
return true
}
State.DEAD -> return false
State.FAILED -> return false
}
}
}
private fun next(): LuaStatus {
val value = nextValue ?: throw IllegalStateException("No next value")
nextValue = null
return value
}
override fun resumeWith(result: Result<Unit>) {
result.getOrThrow()
if (state == State.FAILED || state == State.DEAD) {
throw IllegalStateException("Resuming coroutine in bad state: $state")
}
}
override val context: CoroutineContext
get() = EmptyCoroutineContext
}
suspend fun createLuaScope(block: suspend LuaCoroutineScope.() -> Unit): LuaCoroutineCommunication {
val scope = LuaCoroutineScopeImpl()
// This doesn't work since nextStep requires a Continuation<List<TValue<*>>> and block.createCoroutine returns a Continuation<Unit>
// scope.nextStep = block.createCoroutine(scope, scope)
return scope
}