1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-10-18 05:40:08 +00:00

rewrite firstof

This commit is contained in:
2025-09-23 13:37:59 +06:00
parent 2e23f48350
commit 91339fc839
2 changed files with 49 additions and 17 deletions

View File

@@ -32076,7 +32076,8 @@ public final class dev/inmo/tgbotapi/utils/ExtractDataAndJsonFromDecoderKt {
}
public final class dev/inmo/tgbotapi/utils/FirstOfKt {
public static final fun firstOf (Lkotlinx/coroutines/CoroutineScope;[Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun firstOf ([Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun firstOfOrNull ([Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class dev/inmo/tgbotapi/utils/IntProgress100Serializer : kotlinx/serialization/KSerializer {

View File

@@ -1,26 +1,57 @@
package dev.inmo.tgbotapi.utils
import dev.inmo.micro_utils.coroutines.firstOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.merge
import kotlin.coroutines.cancellation.CancellationException
/**
* Launches all provided suspending [deferreds] in this [CoroutineScope] and returns the value
* produced by the first block that completes.
* Executes the given suspend producers in parallel and returns the first successfully produced value, or null
* if none of them produce a value.
*
* - Provide at least one block; otherwise the call will never complete.
* - Cancellation and error propagation semantics are delegated to the underlying
* dev.inmo.micro_utils.coroutines.firstOf implementation.
* Behaviour:
* - All [deferreds] are started concurrently.
* - Failures are ignored except [CancellationException], which is rethrown.
* - As soon as the first value is emitted, upstream flows are cancelled.
*
* @param T The type of the resulting value.
* @param deferreds The suspending blocks to race; they are started eagerly.
* @return The result produced by the first completed block.
* Notes:
* - If every producer fails (without throwing [CancellationException]) or none emits a value, this returns null.
*
* @param T the type of the produced value
* @param deferreds suspend producers that are started in parallel
* @return the first successfully produced value, or null if none produced a value
* @throws CancellationException if the coroutine scope is cancelled or any producer throws it
*/
suspend fun <T> CoroutineScope.firstOf(
suspend fun <T> firstOfOrNull(
vararg deferreds: suspend () -> T
): T = firstOf {
deferreds.forEach {
add {
it()
): T? {
val resultFlow = deferreds.map {
flow {
runCatching {
it()
}.onSuccess {
emit(it)
}.onFailure {
if (it is CancellationException) throw it
}
}
}
}.merge()
return resultFlow.firstOrNull()
}
/**
* Executes the given suspend producers in parallel and returns the first successfully produced value.
*
* This is a non-nullable variant of [firstOfOrNull]. If no producer yields a value, it throws an [IllegalStateException].
*
* @param T the type of the produced value
* @param deferreds suspend producers that are started in parallel
* @return the first successfully produced value
* @throws IllegalStateException if none of the producers yielded a value
* @throws CancellationException if the coroutine scope is cancelled or any producer throws it
*/
suspend fun <T> firstOf(
vararg deferreds: suspend () -> T
): T {
return firstOfOrNull(*deferreds) ?: error("Unable to get result of deferreds")
}