updates in coroutines

This commit is contained in:
InsanusMokrassar 2021-01-19 13:28:50 +06:00
parent abd0cb2031
commit 0d8f844314
4 changed files with 81 additions and 3 deletions

View File

@ -2,6 +2,12 @@
## 0.4.19 ## 0.4.19
* `Coroutines`:
* New extension `Iterable<Deferred>#awaitFirstWithDeferred` has been added to identify which of `Deferred`s was
normally completed
* New extensions `Iterable<Deferred<T>>#invokeOnFirst` and `Iterable<DeferredAction<*, O>>.invokeFirstOf` have been
added
## 0.4.18 ## 0.4.18
* `Coroutines`: * `Coroutines`:

View File

@ -3,15 +3,15 @@ package dev.inmo.micro_utils.coroutines
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlin.coroutines.* import kotlin.coroutines.*
suspend fun <T> Iterable<Deferred<T>>.awaitFirst( suspend fun <T> Iterable<Deferred<T>>.awaitFirstWithDeferred(
scope: CoroutineScope, scope: CoroutineScope,
cancelOnResult: Boolean = true cancelOnResult: Boolean = true
): T = suspendCoroutine<T> { continuation -> ): Pair<Deferred<T>, T> = suspendCoroutine<Pair<Deferred<T>, T>> { continuation ->
scope.launch(SupervisorJob()) { scope.launch(SupervisorJob()) {
val scope = this val scope = this
forEach { forEach {
scope.launch { scope.launch {
continuation.resume(it.await()) continuation.resume(it to it.await())
scope.cancel() scope.cancel()
} }
} }
@ -27,6 +27,11 @@ suspend fun <T> Iterable<Deferred<T>>.awaitFirst(
} }
} }
} }
suspend fun <T> Iterable<Deferred<T>>.awaitFirst(
scope: CoroutineScope,
cancelOnResult: Boolean = true
): T = awaitFirstWithDeferred(scope, cancelOnResult).second
suspend fun <T> Iterable<Deferred<T>>.awaitFirst( suspend fun <T> Iterable<Deferred<T>>.awaitFirst(
cancelOthers: Boolean = true cancelOthers: Boolean = true
): T = awaitFirst(CoroutineScope(coroutineContext), cancelOthers) ): T = awaitFirst(CoroutineScope(coroutineContext), cancelOthers)

View File

@ -0,0 +1,40 @@
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())
}
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> invokeOnFirst(
scope: CoroutineScope,
vararg variants: Deferred<T>,
cancelOnResult: Boolean = true,
callback: suspend (T) -> O
): O = variants.toList().invokeOnFirst(scope, cancelOnResult, callback)

View File

@ -0,0 +1,27 @@
package dev.inmo.micro_utils.coroutines
import dev.inmo.micro_utils.coroutines.asDeferred
import dev.inmo.micro_utils.coroutines.launchSynchronously
import kotlinx.coroutines.*
import kotlin.test.*
class DoWithFirstTests {
@Test
fun testHandleOneOf() {
val scope = CoroutineScope(Dispatchers.Default)
val happenedDeferreds = mutableListOf<Int>()
val deferredWhichMustHappen = (-1).asDeferred
scope.launchSynchronously {
scope.launch {
((0 until 100).map {
DeferredAction(
scope.async { delay(10000); it },
happenedDeferreds::add
)
} + DeferredAction(deferredWhichMustHappen, happenedDeferreds::add)).invokeFirstOf(scope)
}.join()
}
assertEquals(1, happenedDeferreds.size)
assertEquals(scope.launchSynchronously { deferredWhichMustHappen.await() }, happenedDeferreds.first())
}
}