mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-03 21:51:59 +00:00 
			
		
		
		
	@@ -1,5 +1,13 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 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())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -40,5 +40,5 @@ dokka_version=1.4.20
 | 
				
			|||||||
# Project data
 | 
					# Project data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group=dev.inmo
 | 
					group=dev.inmo
 | 
				
			||||||
version=0.4.18
 | 
					version=0.4.19
 | 
				
			||||||
android_code_version=22
 | 
					android_code_version=23
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user