package moe.lava.banksia.util import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.flow.AbstractFlow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first import moe.lava.banksia.log import kotlin.experimental.ExperimentalTypeInference @OptIn(ExperimentalCoroutinesApi::class) class LoopFlow(private val block: suspend FlowCollector.() -> Unit) : AbstractFlow() { private var delayMs: Long = 5000 private var init: (suspend FlowCollector.() -> Unit)? = null private var waiter: (suspend () -> Unit)? = null override suspend fun collectSafely(collector: FlowCollector) { init?.invoke(collector) while (true) { waiter?.invoke() collector.block() delay(delayMs) } } companion object { fun Flow.delayFor(delay: Long) = apply { @Suppress("UnusedFlow") if (this is LoopFlow) this.delayMs = delay; else throw IllegalStateException() } fun Flow.initWith(block: suspend FlowCollector.() -> Unit) = apply { @Suppress("UnusedFlow") if (this is LoopFlow) this.init = block; else throw IllegalStateException() } fun Flow.waitFor(waiter: suspend () -> Unit) = apply { @Suppress("UnusedFlow") if (this is LoopFlow) this.waiter = waiter; else throw IllegalStateException() } fun Flow.waitUntilSubscribed(other: MutableStateFlow<*>) = waitFor { val blocked = other.subscriptionCount.value == 0 if (blocked) log("LoopFlow", "blocking flow") other.subscriptionCount.first { it > 0 } if (blocked) log("LoopFlow", "unblocking flow") } } } @OptIn(ExperimentalTypeInference::class) fun loopFlow(@BuilderInference block: suspend FlowCollector.() -> Unit) = LoopFlow(block)