commonMain.org.luaj.vm2.internal.RunBlockingNonSuspensions.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of luak-jvm Show documentation
Show all versions of luak-jvm Show documentation
LUAK - Kotlin port of LuaJ (fork of https://github.com/korlibs/korge-luak)
package org.luaj.vm2.internal
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
import kotlin.coroutines.intrinsics.startCoroutineUninterceptedOrReturn
fun runBlockingNoSuspensionsNullable(callback: suspend () -> T): T {
return runBlockingNoSuspensions {
Result.success(callback())
}.getOrThrow()
}
/**
* Allows to execute a suspendable block as long as you can ensure no suspending will happen at all..
*/
fun T.noSuspend(callback: suspend T.() -> R): R {
return runBlockingNoSuspensions { callback(this@noSuspend) }
}
/**
* Allows to execute a suspendable block as long as you can ensure no suspending will happen at all..
*/
//@OptIn(InternalCoroutinesApi::class)
fun runBlockingNoSuspensions(callback: suspend () -> T): T {
//println("!!!!! runBlockingNoSuspensions")
//TODO("runBlockingNoSuspensions not supported yet!")
var completed = false
lateinit var rresult: T
var resultEx: Throwable? = null
var suspendCount = 0
callback.startCoroutineUndispatched(object : Continuation {
override val context: CoroutineContext = object : AbstractCoroutineContextElement(ContinuationInterceptor),
ContinuationInterceptor {//, Delay {
override val key: CoroutineContext.Key<*> = ContinuationInterceptor.Key
override fun interceptContinuation(continuation: Continuation): Continuation = continuation.also { suspendCount++ }
//override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) = continuation.resume(Unit)
}
private val unitInstance get() = Unit
override fun resumeWith(result: Result) {
val exception = result.exceptionOrNull()
if (exception != null) {
resultEx = exception
completed = true
//println("COMPLETED WITH EXCEPTION: exception=$exception")
exception.printStackTrace()
} else {
val rvalue = result.getOrThrow() ?: (unitInstance as T) // @TODO: Kotlin-js BUG returns undefined instead of Unit! In runBlockingNoSuspensions { uncompress(i.toAsyncInputStream(), o.toAsyncOutputStream()) }
//if (rvalue == null) error("ERROR: unexpected completed value=$value, rvalue=$rvalue, suspendCount=$suspendCount")
rresult = rvalue
completed = true
//println("COMPLETED WITH RESULT: result=$result, value=$rvalue")
}
}
})
if (!completed) throw Exception("runBlockingNoSuspensions was not completed synchronously! suspendCount=$suspendCount")
if (resultEx != null) throw resultEx!!
return rresult
}
private fun (suspend () -> T).startCoroutineUndispatched(completion: Continuation) {
startDirect(completion) {
withCoroutineContext(completion.context, null) {
startCoroutineUninterceptedOrReturn(completion)
}
}
}
private inline fun startDirect(completion: Continuation, block: () -> Any?) {
val value = try {
block()
} catch (e: Throwable) {
completion.resumeWithException(e)
return
}
if (value !== COROUTINE_SUSPENDED) {
@Suppress("UNCHECKED_CAST")
completion.resume(value as T)
}
}
private inline fun withCoroutineContext(context: CoroutineContext, countOrElement: Any?, block: () -> T): T = block()