From a3087cb65015da02f980a85698ba208aa55b32b4 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 17 Jan 2021 17:15:54 +0600 Subject: [PATCH] awaitFirst --- CHANGELOG.md | 2 ++ .../inmo/micro_utils/coroutines/AwaitFirst.kt | 32 +++++++++++++++++ .../micro_utils/coroutines/AwaitFirstTests.kt | 34 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/AwaitFirst.kt create mode 100644 coroutines/src/jvmTest/kotlin/dev/inmo/micro_utils/coroutines/AwaitFirstTests.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index b9eb10bffc7..7d5ff380ae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## 0.4.18 +* `Coroutines`: + * New extension `Iterable#awaitFirst` has been added * `Serialization` * `Base 64` * New `Base64ByteArraySerializer` has been added diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/AwaitFirst.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/AwaitFirst.kt new file mode 100644 index 00000000000..c66a830c2b4 --- /dev/null +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/AwaitFirst.kt @@ -0,0 +1,32 @@ +package dev.inmo.micro_utils.coroutines + +import kotlinx.coroutines.* +import kotlin.coroutines.* + +suspend fun Iterable>.awaitFirst( + scope: CoroutineScope, + cancelOnResult: Boolean = true +): T = suspendCoroutine { continuation -> + scope.launch(SupervisorJob()) { + val scope = this + forEach { + scope.launch { + continuation.resume(it.await()) + scope.cancel() + } + } + } +}.also { + if (cancelOnResult) { + forEach { + try { + it.cancel() + } catch (e: IllegalStateException) { + e.printStackTrace() + } + } + } +} +suspend fun Iterable>.awaitFirst( + cancelOthers: Boolean = true +): T = awaitFirst(CoroutineScope(coroutineContext), cancelOthers) diff --git a/coroutines/src/jvmTest/kotlin/dev/inmo/micro_utils/coroutines/AwaitFirstTests.kt b/coroutines/src/jvmTest/kotlin/dev/inmo/micro_utils/coroutines/AwaitFirstTests.kt new file mode 100644 index 00000000000..82f75db1242 --- /dev/null +++ b/coroutines/src/jvmTest/kotlin/dev/inmo/micro_utils/coroutines/AwaitFirstTests.kt @@ -0,0 +1,34 @@ +package dev.inmo.micro_utils.coroutines + +import kotlinx.coroutines.* +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class AwaitFirstTests { + private fun CoroutineScope.createTestDeferred(value: Int, wait: Long = 100000) = async(start = CoroutineStart.LAZY) { delay(wait); value } + @Test + fun testThatAwaitFirstIsWorkingCorrectly() { + val baseScope = CoroutineScope(Dispatchers.Default) + val resultDeferred = baseScope.createTestDeferred(-1, 0) + val deferreds = listOf( + baseScope.async { createTestDeferred(0) }, + baseScope.async { createTestDeferred(1) }, + baseScope.async { createTestDeferred(2) }, + resultDeferred + ) + val controlJob = baseScope.launch { + delay(1000000) + } + val result = baseScope.launchSynchronously { + val result = deferreds.awaitFirst(baseScope) + + assertTrue(baseScope.isActive) + assertTrue(controlJob.isActive) + + result + } + assertEquals(baseScope.launchSynchronously { resultDeferred.await() }, result) + assertTrue(deferreds.all { it == resultDeferred || it.isCancelled }) + } +} \ No newline at end of file