mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-10-26 09:40:26 +00:00 
			
		
		
		
	updates in coroutines
This commit is contained in:
		| @@ -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`: | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
| @@ -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) | ||||||
| @@ -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()) | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user