All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmMain.org.openrndr.CoroutineDispatcher.kt Maven / Gradle / Ivy

The newest version!
package org.openrndr

import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext

private val logger = KotlinLogging.logger {}


private var lastRunTime = -1L

@OptIn(InternalCoroutinesApi::class)
actual class Dispatcher : MainCoroutineDispatcher(), Delay {
    private val toRun = mutableListOf()
    private val toRunAfter = mutableListOf>()
    private val toContinueAfter = mutableListOf>>()


    override fun isDispatchNeeded(context: CoroutineContext): Boolean = true
    override fun toString(): String {
        return "MainCoroutineDispatcher"
    }

    override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) {
        synchronized(toContinueAfter) {
            logger.trace { "scheduleResume $timeMillis $continuation" }
            toContinueAfter.add(Pair(System.currentTimeMillis() + timeMillis, continuation))
        }
    }


    override val immediate: MainCoroutineDispatcher
        get() = this

    override fun dispatch(context: CoroutineContext, block: Runnable) {
        synchronized(toRun) {
            logger.trace { "dispatching $block" }
            toRun.add(block)
        }
    }

    val shouldExecute : Boolean
        get() {
            val time = System.currentTimeMillis()
            return toRun.isNotEmpty() || toRunAfter.any { it.first <= time } || toContinueAfter.any { it.first <= time }
        }

    @OptIn(ExperimentalCoroutinesApi::class)
    fun execute() {
        lastRunTime = System.currentTimeMillis()
        synchronized(toRun) {
            val copy = toRun + emptyList()
            toRun.clear()
            copy.forEach {
                logger.trace { "running $it" }
                it.run()
            }
        }

        val time = System.currentTimeMillis()
        synchronized(toRunAfter) {
            val toDo = toRunAfter.filter { it.first <= time }
            if (toDo.isNotEmpty()) {
                toRunAfter.removeAll { it.first <= time }
            }
            for ((_, runnable) in toDo) {
                logger.trace { "running $runnable" }
                runnable.run()
            }
        }

        synchronized(toContinueAfter) {
            val toDo = toContinueAfter.filter { it.first <= time }
            if (toDo.isNotEmpty()) {
                toContinueAfter.removeAll { it.first <= time }
            }
            for ((_, continuation) in toDo) {
                with(continuation) {
                    logger.trace { "resuming $continuation" }
                    @Suppress("EXPERIMENTAL_API_USAGE")
                    resumeUndispatched(Unit)
                }
            }
        }
    }
}

suspend fun throttle(timeMillis: Long) {
    if ((System.currentTimeMillis() - lastRunTime) > timeMillis) {
        delay(1)
    }
}


@OptIn(DelicateCoroutinesApi::class)
fun Dispatcher.launch(start: CoroutineStart = CoroutineStart.DEFAULT,
                      block: suspend CoroutineScope.() -> Unit
): Job = GlobalScope.launch(this, start, block)





© 2015 - 2025 Weber Informatics LLC | Privacy Policy