86 lines
2.7 KiB
Kotlin
86 lines
2.7 KiB
Kotlin
package dev.inmo.micro_utils.coroutines
|
|
|
|
import kotlinx.coroutines.*
|
|
|
|
class DeferredAction<T, O>(
|
|
val deferred: Deferred<T>,
|
|
val callback: suspend (T) -> O
|
|
) {
|
|
suspend operator fun invoke() = callback(deferred.await())
|
|
}
|
|
|
|
class DoWithFirstBuilder<T>(
|
|
private val scope: CoroutineScope
|
|
) {
|
|
private val deferreds = mutableListOf<Deferred<T>>()
|
|
operator fun plus(block: suspend CoroutineScope.() -> T) {
|
|
deferreds.add(scope.async(start = CoroutineStart.LAZY, block = block))
|
|
}
|
|
inline fun add(noinline block: suspend CoroutineScope.() -> T) = plus(block)
|
|
inline fun include(noinline block: suspend CoroutineScope.() -> T) = plus(block)
|
|
|
|
fun build() = deferreds.toList()
|
|
}
|
|
|
|
fun <T, O> Deferred<T>.buildAction(callback: suspend (T) -> O) = DeferredAction(this, callback)
|
|
|
|
suspend fun <O> Iterable<DeferredAction<*, O>>.invokeFirstOf(
|
|
scope: CoroutineScope,
|
|
cancelOnResult: Boolean = true
|
|
): O {
|
|
return map { it.deferred }.awaitFirstWithDeferred(scope, cancelOnResult).let { result ->
|
|
first { it.deferred == result.first }.invoke()
|
|
}
|
|
}
|
|
|
|
suspend fun <O> invokeFirstOf(
|
|
scope: CoroutineScope,
|
|
vararg variants: DeferredAction<*, O>,
|
|
cancelOnResult: Boolean = true
|
|
): O = variants.toList().invokeFirstOf(scope, cancelOnResult)
|
|
|
|
suspend fun <T, O> Iterable<Deferred<T>>.invokeOnFirst(
|
|
scope: CoroutineScope,
|
|
cancelOnResult: Boolean = true,
|
|
callback: suspend (T) -> O
|
|
): O = map { it.buildAction(callback) }.invokeFirstOf(scope, cancelOnResult)
|
|
|
|
suspend fun <T, O> CoroutineScope.invokeOnFirstOf(
|
|
cancelOnResult: Boolean = true,
|
|
block: DoWithFirstBuilder<T>.() -> Unit,
|
|
callback: suspend (T) -> O
|
|
) = firstOf(
|
|
DoWithFirstBuilder<T>(this).apply(block).build(),
|
|
cancelOnResult
|
|
).let { callback(it) }
|
|
|
|
suspend fun <T, O> invokeOnFirst(
|
|
scope: CoroutineScope,
|
|
vararg variants: Deferred<T>,
|
|
cancelOnResult: Boolean = true,
|
|
callback: suspend (T) -> O
|
|
): O = variants.toList().invokeOnFirst(scope, cancelOnResult, callback)
|
|
|
|
suspend fun <T> CoroutineScope.firstOf(
|
|
variants: Iterable<Deferred<T>>,
|
|
cancelOnResult: Boolean = true
|
|
) = variants.invokeOnFirst(this, cancelOnResult) { it }
|
|
|
|
suspend fun <T> CoroutineScope.firstOf(
|
|
cancelOnResult: Boolean = true,
|
|
block: DoWithFirstBuilder<T>.() -> Unit
|
|
) = firstOf(
|
|
DoWithFirstBuilder<T>(this).apply(block).build(),
|
|
cancelOnResult
|
|
)
|
|
|
|
suspend fun <T> CoroutineScope.firstOf(
|
|
vararg variants: Deferred<T>,
|
|
cancelOnResult: Boolean = true
|
|
) = firstOf(variants.toList(), cancelOnResult)
|
|
|
|
suspend fun <T> List<Deferred<T>>.first(
|
|
scope: CoroutineScope,
|
|
cancelOnResult: Boolean = true
|
|
) = scope.firstOf(this, cancelOnResult)
|