mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2026-03-11 12:52:23 +00:00
generate docs for a lot of API (test try)
This commit is contained in:
@@ -5,6 +5,18 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.consumeAsFlow
|
||||
|
||||
/**
|
||||
* Creates an actor-style channel that processes messages asynchronously based on markers.
|
||||
* Messages with the same marker will be processed sequentially, while messages with different markers can be processed concurrently.
|
||||
*
|
||||
* @param T The type of messages to process
|
||||
* @param channelCapacity The capacity of the underlying channel. Defaults to [Channel.UNLIMITED]
|
||||
* @param markerFactory A factory function that produces a marker for each message. Messages with the same marker
|
||||
* will be processed sequentially. Defaults to returning null, meaning all messages will be processed sequentially
|
||||
* @param logger The logger instance used for logging exceptions. Defaults to [KSLog]
|
||||
* @param block The suspending function that processes each message
|
||||
* @return A [Channel] that accepts messages to be processed
|
||||
*/
|
||||
fun <T> CoroutineScope.actorAsync(
|
||||
channelCapacity: Int = Channel.UNLIMITED,
|
||||
markerFactory: suspend (T) -> Any? = { null },
|
||||
|
||||
@@ -3,5 +3,12 @@ package dev.inmo.micro_utils.coroutines
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.Deferred
|
||||
|
||||
/**
|
||||
* Wraps this value in a completed [Deferred]. The resulting [Deferred] is immediately completed with this value.
|
||||
* Useful for converting synchronous values to [Deferred] in contexts that expect deferred values.
|
||||
*
|
||||
* @param T The type of the value
|
||||
* @return A [Deferred] that is already completed with this value
|
||||
*/
|
||||
val <T> T.asDeferred: Deferred<T>
|
||||
get() = CompletableDeferred(this)
|
||||
|
||||
@@ -3,20 +3,53 @@ package dev.inmo.micro_utils.coroutines
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* Convenience property to access [Dispatchers.Main] for UI operations.
|
||||
*/
|
||||
inline val UI
|
||||
get() = Dispatchers.Main
|
||||
|
||||
/**
|
||||
* Convenience property to access [Dispatchers.Default] for CPU-intensive operations.
|
||||
*/
|
||||
inline val Default
|
||||
get() = Dispatchers.Default
|
||||
|
||||
/**
|
||||
* Executes the given [block] in the specified coroutine [context] and returns its result.
|
||||
* This is a convenience wrapper around [withContext].
|
||||
*
|
||||
* @param T The return type of the block
|
||||
* @param context The [CoroutineContext] in which to execute the block
|
||||
* @param block The suspending function to execute
|
||||
* @return The result of executing the block
|
||||
*/
|
||||
suspend inline fun <T> doIn(context: CoroutineContext, noinline block: suspend CoroutineScope.() -> T) = withContext(
|
||||
context,
|
||||
block
|
||||
)
|
||||
|
||||
/**
|
||||
* Executes the given [block] on the UI/Main dispatcher and returns its result.
|
||||
* This is a convenience function for executing UI operations.
|
||||
*
|
||||
* @param T The return type of the block
|
||||
* @param block The suspending function to execute on the UI thread
|
||||
* @return The result of executing the block
|
||||
*/
|
||||
suspend inline fun <T> doInUI(noinline block: suspend CoroutineScope.() -> T) = doIn(
|
||||
UI,
|
||||
block
|
||||
)
|
||||
|
||||
/**
|
||||
* Executes the given [block] on the Default dispatcher and returns its result.
|
||||
* This is a convenience function for executing CPU-intensive operations.
|
||||
*
|
||||
* @param T The return type of the block
|
||||
* @param block The suspending function to execute on the Default dispatcher
|
||||
* @return The result of executing the block
|
||||
*/
|
||||
suspend inline fun <T> doInDefault(noinline block: suspend CoroutineScope.() -> T) = doIn(
|
||||
Default,
|
||||
block
|
||||
|
||||
@@ -2,6 +2,14 @@ package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
/**
|
||||
* Represents a deferred action that combines a [Deferred] value with a callback to be executed on that value.
|
||||
*
|
||||
* @param T The type of the deferred value
|
||||
* @param O The type of the result after applying the callback
|
||||
* @param deferred The deferred value to await
|
||||
* @param callback The suspending function to apply to the deferred value
|
||||
*/
|
||||
class DeferredAction<T, O>(
|
||||
val deferred: Deferred<T>,
|
||||
val callback: suspend (T) -> O
|
||||
@@ -9,6 +17,13 @@ class DeferredAction<T, O>(
|
||||
suspend operator fun invoke() = callback(deferred.await())
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for creating multiple deferred computations that can be executed, with only the first completing
|
||||
* one being used. This is useful for race conditions where you want the result of whichever computation finishes first.
|
||||
*
|
||||
* @param T The type of values produced by the deferred computations
|
||||
* @param scope The [CoroutineScope] in which to create the deferred computations
|
||||
*/
|
||||
class DoWithFirstBuilder<T>(
|
||||
private val scope: CoroutineScope
|
||||
) {
|
||||
@@ -22,8 +37,25 @@ class DoWithFirstBuilder<T>(
|
||||
fun build() = deferreds.toList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [DeferredAction] from this [Deferred] and a [callback] function.
|
||||
*
|
||||
* @param T The type of the deferred value
|
||||
* @param O The type of the result after applying the callback
|
||||
* @param callback The suspending function to apply to the deferred value
|
||||
* @return A [DeferredAction] combining the deferred and callback
|
||||
*/
|
||||
fun <T, O> Deferred<T>.buildAction(callback: suspend (T) -> O) = DeferredAction(this, callback)
|
||||
|
||||
/**
|
||||
* Invokes the first [DeferredAction] whose deferred value completes, executing its callback and returning the result.
|
||||
* Other deferred actions are cancelled if [cancelOnResult] is true.
|
||||
*
|
||||
* @param O The type of the result after applying callbacks
|
||||
* @param scope The [CoroutineScope] in which to await the deferred values
|
||||
* @param cancelOnResult If true, cancels all other deferred actions after the first completes. Defaults to true
|
||||
* @return The result of invoking the first completed deferred action
|
||||
*/
|
||||
suspend fun <O> Iterable<DeferredAction<*, O>>.invokeFirstOf(
|
||||
scope: CoroutineScope,
|
||||
cancelOnResult: Boolean = true
|
||||
@@ -33,18 +65,50 @@ suspend fun <O> Iterable<DeferredAction<*, O>>.invokeFirstOf(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the first [DeferredAction] from the given [variants] whose deferred value completes,
|
||||
* executing its callback and returning the result. Other deferred actions are cancelled if [cancelOnResult] is true.
|
||||
*
|
||||
* @param O The type of the result after applying callbacks
|
||||
* @param scope The [CoroutineScope] in which to await the deferred values
|
||||
* @param variants The deferred actions to race
|
||||
* @param cancelOnResult If true, cancels all other deferred actions after the first completes. Defaults to true
|
||||
* @return The result of invoking the first completed deferred action
|
||||
*/
|
||||
suspend fun <O> invokeFirstOf(
|
||||
scope: CoroutineScope,
|
||||
vararg variants: DeferredAction<*, O>,
|
||||
cancelOnResult: Boolean = true
|
||||
): O = variants.toList().invokeFirstOf(scope, cancelOnResult)
|
||||
|
||||
/**
|
||||
* Awaits the first [Deferred] to complete and invokes the [callback] on its value.
|
||||
* Other deferred values are cancelled if [cancelOnResult] is true.
|
||||
*
|
||||
* @param T The type of the deferred values
|
||||
* @param O The type of the result after applying the callback
|
||||
* @param scope The [CoroutineScope] in which to await the deferred values
|
||||
* @param cancelOnResult If true, cancels all other deferred values after the first completes. Defaults to true
|
||||
* @param callback The suspending function to apply to the first completed value
|
||||
* @return The result of applying the callback to the first completed value
|
||||
*/
|
||||
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)
|
||||
|
||||
/**
|
||||
* Builds multiple deferred computations using [DoWithFirstBuilder] and invokes [callback] on the first one to complete.
|
||||
* Other deferred computations are cancelled if [cancelOnResult] is true.
|
||||
*
|
||||
* @param T The type of the deferred values
|
||||
* @param O The type of the result after applying the callback
|
||||
* @param cancelOnResult If true, cancels all other computations after the first completes. Defaults to true
|
||||
* @param block Builder DSL to define the deferred computations
|
||||
* @param callback The suspending function to apply to the first completed value
|
||||
* @return The result of applying the callback to the first completed value
|
||||
*/
|
||||
suspend fun <T, O> CoroutineScope.invokeOnFirstOf(
|
||||
cancelOnResult: Boolean = true,
|
||||
block: DoWithFirstBuilder<T>.() -> Unit,
|
||||
@@ -54,6 +118,18 @@ suspend fun <T, O> CoroutineScope.invokeOnFirstOf(
|
||||
cancelOnResult
|
||||
).let { callback(it) }
|
||||
|
||||
/**
|
||||
* Awaits the first [Deferred] from the given [variants] to complete and invokes the [callback] on its value.
|
||||
* Other deferred values are cancelled if [cancelOnResult] is true.
|
||||
*
|
||||
* @param T The type of the deferred values
|
||||
* @param O The type of the result after applying the callback
|
||||
* @param scope The [CoroutineScope] in which to await the deferred values
|
||||
* @param variants The deferred values to race
|
||||
* @param cancelOnResult If true, cancels all other deferred values after the first completes. Defaults to true
|
||||
* @param callback The suspending function to apply to the first completed value
|
||||
* @return The result of applying the callback to the first completed value
|
||||
*/
|
||||
suspend fun <T, O> invokeOnFirst(
|
||||
scope: CoroutineScope,
|
||||
vararg variants: Deferred<T>,
|
||||
@@ -61,11 +137,29 @@ suspend fun <T, O> invokeOnFirst(
|
||||
callback: suspend (T) -> O
|
||||
): O = variants.toList().invokeOnFirst(scope, cancelOnResult, callback)
|
||||
|
||||
/**
|
||||
* Returns the value of the first [Deferred] from the given [variants] to complete.
|
||||
* Other deferred values are cancelled if [cancelOnResult] is true.
|
||||
*
|
||||
* @param T The type of the deferred values
|
||||
* @param variants The deferred values to race
|
||||
* @param cancelOnResult If true, cancels all other deferred values after the first completes. Defaults to true
|
||||
* @return The value of the first completed deferred
|
||||
*/
|
||||
suspend fun <T> CoroutineScope.firstOf(
|
||||
variants: Iterable<Deferred<T>>,
|
||||
cancelOnResult: Boolean = true
|
||||
) = variants.invokeOnFirst(this, cancelOnResult) { it }
|
||||
|
||||
/**
|
||||
* Builds multiple deferred computations using [DoWithFirstBuilder] and returns the value of the first one to complete.
|
||||
* Other deferred computations are cancelled if [cancelOnResult] is true.
|
||||
*
|
||||
* @param T The type of the deferred values
|
||||
* @param cancelOnResult If true, cancels all other computations after the first completes. Defaults to true
|
||||
* @param block Builder DSL to define the deferred computations
|
||||
* @return The value of the first completed computation
|
||||
*/
|
||||
suspend fun <T> CoroutineScope.firstOf(
|
||||
cancelOnResult: Boolean = true,
|
||||
block: DoWithFirstBuilder<T>.() -> Unit
|
||||
@@ -74,11 +168,29 @@ suspend fun <T> CoroutineScope.firstOf(
|
||||
cancelOnResult
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns the value of the first [Deferred] from the given [variants] to complete.
|
||||
* Other deferred values are cancelled if [cancelOnResult] is true.
|
||||
*
|
||||
* @param T The type of the deferred values
|
||||
* @param variants The deferred values to race
|
||||
* @param cancelOnResult If true, cancels all other deferred values after the first completes. Defaults to true
|
||||
* @return The value of the first completed deferred
|
||||
*/
|
||||
suspend fun <T> CoroutineScope.firstOf(
|
||||
vararg variants: Deferred<T>,
|
||||
cancelOnResult: Boolean = true
|
||||
) = firstOf(variants.toList(), cancelOnResult)
|
||||
|
||||
/**
|
||||
* Returns the value of the first [Deferred] from this list to complete, using the given [scope].
|
||||
* Other deferred values are cancelled if [cancelOnResult] is true.
|
||||
*
|
||||
* @param T The type of the deferred values
|
||||
* @param scope The [CoroutineScope] in which to await the deferred values
|
||||
* @param cancelOnResult If true, cancels all other deferred values after the first completes. Defaults to true
|
||||
* @return The value of the first completed deferred
|
||||
*/
|
||||
suspend fun <T> List<Deferred<T>>.first(
|
||||
scope: CoroutineScope,
|
||||
cancelOnResult: Boolean = true
|
||||
|
||||
@@ -2,4 +2,11 @@ package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
|
||||
/**
|
||||
* Operator function that allows a [FlowCollector] to be invoked like a function to emit a value.
|
||||
* This is a convenient syntax sugar for [FlowCollector.emit].
|
||||
*
|
||||
* @param T The type of values the collector can emit
|
||||
* @param value The value to emit
|
||||
*/
|
||||
suspend inline operator fun <T> FlowCollector<T>.invoke(value: T) = emit(value)
|
||||
|
||||
@@ -14,6 +14,15 @@ private value class DebouncedByData<T>(
|
||||
val millisToData: Pair<Long, T>
|
||||
)
|
||||
|
||||
/**
|
||||
* Debounces a [Flow] with per-marker timeout control. Values with the same marker will be debounced independently.
|
||||
* For each marker, only the last value within the timeout period will be emitted.
|
||||
*
|
||||
* @param T The type of values emitted by the flow
|
||||
* @param timeout A function that determines the debounce timeout in milliseconds for each value
|
||||
* @param markerFactory A function that produces a marker for each value. Values with the same marker are debounced together
|
||||
* @return A [Flow] that emits debounced values
|
||||
*/
|
||||
fun <T> Flow<T>.debouncedBy(timeout: (T) -> Long, markerFactory: (T) -> Any?): Flow<T> = channelFlow {
|
||||
val jobs = mutableMapOf<Any?, Job>()
|
||||
val mutex = Mutex()
|
||||
@@ -36,5 +45,24 @@ fun <T> Flow<T>.debouncedBy(timeout: (T) -> Long, markerFactory: (T) -> Any?): F
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debounces a [Flow] with a fixed timeout in milliseconds and per-marker control.
|
||||
* Values with the same marker will be debounced independently.
|
||||
*
|
||||
* @param T The type of values emitted by the flow
|
||||
* @param timeout The debounce timeout in milliseconds
|
||||
* @param markerFactory A function that produces a marker for each value. Values with the same marker are debounced together
|
||||
* @return A [Flow] that emits debounced values
|
||||
*/
|
||||
fun <T> Flow<T>.debouncedBy(timeout: Long, markerFactory: (T) -> Any?): Flow<T> = debouncedBy({ timeout }, markerFactory)
|
||||
|
||||
/**
|
||||
* Debounces a [Flow] with a fixed timeout as [Duration] and per-marker control.
|
||||
* Values with the same marker will be debounced independently.
|
||||
*
|
||||
* @param T The type of values emitted by the flow
|
||||
* @param timeout The debounce timeout as a [Duration]
|
||||
* @param markerFactory A function that produces a marker for each value. Values with the same marker are debounced together
|
||||
* @return A [Flow] that emits debounced values
|
||||
*/
|
||||
fun <T> Flow<T>.debouncedBy(timeout: Duration, markerFactory: (T) -> Any?): Flow<T> = debouncedBy({ timeout.inWholeMilliseconds }, markerFactory)
|
||||
|
||||
@@ -3,4 +3,12 @@ package dev.inmo.micro_utils.coroutines
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
/**
|
||||
* Returns the first non-null element emitted by this [Flow].
|
||||
* Suspends until a non-null element is found.
|
||||
*
|
||||
* @param T The type of elements in the flow
|
||||
* @return The first non-null element
|
||||
* @throws NoSuchElementException if the flow completes without emitting a non-null element
|
||||
*/
|
||||
suspend fun <T> Flow<T?>.firstNotNull() = first { it != null }!!
|
||||
|
||||
@@ -4,6 +4,14 @@ import kotlinx.coroutines.flow.*
|
||||
import kotlin.js.JsName
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
/**
|
||||
* Transforms each inner [Flow] element using the given [mapper] function and flattens the result into a single [Flow].
|
||||
*
|
||||
* @param T The type of elements in the inner flows
|
||||
* @param R The type of elements after applying the mapper
|
||||
* @param mapper A suspending function to transform each element
|
||||
* @return A [Flow] of mapped and flattened elements
|
||||
*/
|
||||
inline fun <T, R> Flow<Flow<T>>.flatMap(
|
||||
crossinline mapper: suspend (T) -> R
|
||||
) = flow {
|
||||
@@ -14,6 +22,14 @@ inline fun <T, R> Flow<Flow<T>>.flatMap(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms each element from inner [Iterable]s using the given [mapper] function and flattens the result into a single [Flow].
|
||||
*
|
||||
* @param T The type of elements in the iterables
|
||||
* @param R The type of elements after applying the mapper
|
||||
* @param mapper A suspending function to transform each element
|
||||
* @return A [Flow] of mapped and flattened elements
|
||||
*/
|
||||
@JsName("flatMapIterable")
|
||||
@JvmName("flatMapIterable")
|
||||
inline fun <T, R> Flow<Iterable<T>>.flatMap(
|
||||
@@ -22,18 +38,48 @@ inline fun <T, R> Flow<Iterable<T>>.flatMap(
|
||||
it.asFlow()
|
||||
}.flatMap(mapper)
|
||||
|
||||
/**
|
||||
* Transforms each inner [Flow] element using the given [mapper] function, flattens the result,
|
||||
* and filters out null values.
|
||||
*
|
||||
* @param T The type of elements in the inner flows
|
||||
* @param R The type of elements after applying the mapper
|
||||
* @param mapper A suspending function to transform each element
|
||||
* @return A [Flow] of non-null mapped and flattened elements
|
||||
*/
|
||||
inline fun <T, R> Flow<Flow<T>>.flatMapNotNull(
|
||||
crossinline mapper: suspend (T) -> R
|
||||
) = flatMap(mapper).takeNotNull()
|
||||
|
||||
/**
|
||||
* Transforms each element from inner [Iterable]s using the given [mapper] function, flattens the result,
|
||||
* and filters out null values.
|
||||
*
|
||||
* @param T The type of elements in the iterables
|
||||
* @param R The type of elements after applying the mapper
|
||||
* @param mapper A suspending function to transform each element
|
||||
* @return A [Flow] of non-null mapped and flattened elements
|
||||
*/
|
||||
@JsName("flatMapNotNullIterable")
|
||||
@JvmName("flatMapNotNullIterable")
|
||||
inline fun <T, R> Flow<Iterable<T>>.flatMapNotNull(
|
||||
crossinline mapper: suspend (T) -> R
|
||||
) = flatMap(mapper).takeNotNull()
|
||||
|
||||
/**
|
||||
* Flattens a [Flow] of [Flow]s into a single [Flow] by collecting all inner flows sequentially.
|
||||
*
|
||||
* @param T The type of elements in the inner flows
|
||||
* @return A [Flow] containing all elements from all inner flows
|
||||
*/
|
||||
fun <T> Flow<Flow<T>>.flatten() = flatMap { it }
|
||||
|
||||
/**
|
||||
* Flattens a [Flow] of [Iterable]s into a single [Flow] by emitting all elements from each iterable.
|
||||
*
|
||||
* @param T The type of elements in the iterables
|
||||
* @return A [Flow] containing all elements from all iterables
|
||||
*/
|
||||
@JsName("flattenIterable")
|
||||
@JvmName("flattenIterable")
|
||||
fun <T> Flow<Iterable<T>>.flatten() = flatMap { it }
|
||||
|
||||
@@ -2,5 +2,18 @@ package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
/**
|
||||
* Filters out null values from this [Flow], returning only non-null elements.
|
||||
*
|
||||
* @param T The type of elements in the flow (nullable)
|
||||
* @return A [Flow] containing only non-null elements
|
||||
*/
|
||||
fun <T> Flow<T>.takeNotNull() = mapNotNull { it }
|
||||
|
||||
/**
|
||||
* Alias for [takeNotNull]. Filters out null values from this [Flow], returning only non-null elements.
|
||||
*
|
||||
* @param T The type of elements in the flow (nullable)
|
||||
* @return A [Flow] containing only non-null elements
|
||||
*/
|
||||
fun <T> Flow<T>.filterNotNull() = takeNotNull()
|
||||
|
||||
@@ -65,6 +65,20 @@ private data class AsyncSubscriptionCommandClearReceiver<T, M>(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to a [Flow] with asynchronous processing based on markers.
|
||||
* Each value from the flow will be processed by the [block] function. Values with the same marker
|
||||
* will be processed sequentially in the same coroutine scope, while values with different markers
|
||||
* can be processed concurrently in separate coroutine scopes.
|
||||
*
|
||||
* @param T The type of values emitted by the flow
|
||||
* @param M The type of markers used to group values
|
||||
* @param scope The [CoroutineScope] in which to subscribe to the flow
|
||||
* @param markerFactory A factory function that produces a marker for each emitted value
|
||||
* @param logger The logger instance used for logging exceptions. Defaults to [KSLog]
|
||||
* @param block The suspending function that processes each emitted value
|
||||
* @return A [Job] representing the subscription that can be cancelled
|
||||
*/
|
||||
fun <T, M> Flow<T>.subscribeAsync(
|
||||
scope: CoroutineScope,
|
||||
markerFactory: suspend (T) -> M,
|
||||
@@ -122,6 +136,20 @@ fun <T, M> Flow<T>.subscribeSafelyWithoutExceptionsAsync(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to a [Flow] with asynchronous processing based on markers, automatically logging and dropping exceptions.
|
||||
* Each value from the flow will be processed by the [block] function. Values with the same marker
|
||||
* will be processed sequentially, while values with different markers can be processed concurrently.
|
||||
* Any exceptions thrown during processing will be logged and dropped without affecting other messages.
|
||||
*
|
||||
* @param T The type of values emitted by the flow
|
||||
* @param M The type of markers used to group values
|
||||
* @param scope The [CoroutineScope] in which to subscribe to the flow
|
||||
* @param markerFactory A factory function that produces a marker for each emitted value
|
||||
* @param logger The logger instance used for logging exceptions. Defaults to [KSLog]
|
||||
* @param block The suspending function that processes each emitted value
|
||||
* @return A [Job] representing the subscription that can be cancelled
|
||||
*/
|
||||
fun <T, M> Flow<T>.subscribeLoggingDropExceptionsAsync(
|
||||
scope: CoroutineScope,
|
||||
markerFactory: suspend (T) -> M,
|
||||
|
||||
@@ -5,4 +5,12 @@ package dev.inmo.micro_utils.coroutines
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.merge
|
||||
|
||||
/**
|
||||
* Merges two flows into a single flow. Values from both flows will be emitted as they become available.
|
||||
* This is a convenient operator syntax for [merge].
|
||||
*
|
||||
* @param T The type of elements in the flows
|
||||
* @param other The flow to merge with this flow
|
||||
* @return A [Flow] that emits values from both flows
|
||||
*/
|
||||
inline operator fun <T> Flow<T>.plus(other: Flow<T>) = merge(this, other)
|
||||
|
||||
@@ -6,6 +6,17 @@ import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
/**
|
||||
* Launches a new coroutine with automatic exception logging. If an exception occurs, it will be logged
|
||||
* using the provided [logger] and then rethrown.
|
||||
*
|
||||
* @param errorMessageBuilder A function to build the error message from the caught exception. Defaults to "Something web wrong"
|
||||
* @param logger The logger instance to use for logging exceptions. Defaults to [KSLog]
|
||||
* @param context Additional [CoroutineContext] for the new coroutine. Defaults to [EmptyCoroutineContext]
|
||||
* @param start The coroutine start option. Defaults to [CoroutineStart.DEFAULT]
|
||||
* @param block The suspending function to execute in the new coroutine
|
||||
* @return A [Job] representing the launched coroutine
|
||||
*/
|
||||
fun CoroutineScope.launchLogging(
|
||||
errorMessageBuilder: CoroutineScope.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
@@ -18,6 +29,17 @@ fun CoroutineScope.launchLogging(
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a new coroutine with automatic exception logging and dropping. If an exception occurs, it will be logged
|
||||
* using the provided [logger] and then dropped (not rethrown), allowing the coroutine to complete normally.
|
||||
*
|
||||
* @param errorMessageBuilder A function to build the error message from the caught exception. Defaults to "Something web wrong"
|
||||
* @param logger The logger instance to use for logging exceptions. Defaults to [KSLog]
|
||||
* @param context Additional [CoroutineContext] for the new coroutine. Defaults to [EmptyCoroutineContext]
|
||||
* @param start The coroutine start option. Defaults to [CoroutineStart.DEFAULT]
|
||||
* @param block The suspending function to execute in the new coroutine
|
||||
* @return A [Job] representing the launched coroutine
|
||||
*/
|
||||
fun CoroutineScope.launchLoggingDropExceptions(
|
||||
errorMessageBuilder: CoroutineScope.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
@@ -30,6 +52,18 @@ fun CoroutineScope.launchLoggingDropExceptions(
|
||||
} // just dropping exception
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new async coroutine with automatic exception logging. If an exception occurs, it will be logged
|
||||
* using the provided [logger] and then rethrown when the [Deferred] is awaited.
|
||||
*
|
||||
* @param T The return type of the async computation
|
||||
* @param errorMessageBuilder A function to build the error message from the caught exception. Defaults to "Something web wrong"
|
||||
* @param logger The logger instance to use for logging exceptions. Defaults to [KSLog]
|
||||
* @param context Additional [CoroutineContext] for the new coroutine. Defaults to [EmptyCoroutineContext]
|
||||
* @param start The coroutine start option. Defaults to [CoroutineStart.DEFAULT]
|
||||
* @param block The suspending function to execute that returns a value of type [T]
|
||||
* @return A [Deferred] representing the async computation
|
||||
*/
|
||||
fun <T> CoroutineScope.asyncLogging(
|
||||
errorMessageBuilder: CoroutineScope.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
@@ -42,6 +76,18 @@ fun <T> CoroutineScope.asyncLogging(
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new async coroutine with automatic exception logging and dropping. If an exception occurs, it will be logged
|
||||
* using the provided [logger] and wrapped in a [Result], which can be checked when the [Deferred] is awaited.
|
||||
*
|
||||
* @param T The return type of the async computation
|
||||
* @param errorMessageBuilder A function to build the error message from the caught exception. Defaults to "Something web wrong"
|
||||
* @param logger The logger instance to use for logging exceptions. Defaults to [KSLog]
|
||||
* @param context Additional [CoroutineContext] for the new coroutine. Defaults to [EmptyCoroutineContext]
|
||||
* @param start The coroutine start option. Defaults to [CoroutineStart.DEFAULT]
|
||||
* @param block The suspending function to execute that returns a value of type [T]
|
||||
* @return A [Deferred] containing a [Result] representing the async computation
|
||||
*/
|
||||
fun <T> CoroutineScope.asyncLoggingDropExceptions(
|
||||
errorMessageBuilder: CoroutineScope.(Throwable) -> Any = { "Something web wrong" },
|
||||
logger: KSLog = KSLog,
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
/**
|
||||
* Replaces a failed [Result] with a new value computed from the exception.
|
||||
* If this [Result] is successful, it is returned as-is. If it represents a failure,
|
||||
* the [onException] handler is called with the exception to compute a replacement value,
|
||||
* which is then wrapped in a new [Result].
|
||||
*
|
||||
* @param T The type of the successful value
|
||||
* @param onException A function that computes a replacement value from the caught exception
|
||||
* @return The original [Result] if successful, or a new [Result] containing the replacement value
|
||||
*/
|
||||
inline fun <T> Result<T>.replaceIfFailure(onException: (Throwable) -> T) = if (isSuccess) { this } else { runCatching { onException(exceptionOrNull()!!) } }
|
||||
|
||||
@@ -3,6 +3,14 @@ package dev.inmo.micro_utils.coroutines
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
/**
|
||||
* Executes the given [block] and unlocks all provided [lockers] for writing if the block succeeds.
|
||||
* If the block throws an exception, the lockers will remain locked.
|
||||
*
|
||||
* @param lockers Variable number of [SmartRWLocker] instances to unlock on successful execution
|
||||
* @param block The suspending function to execute
|
||||
* @return A [Result] containing [Unit] on success or the exception that occurred
|
||||
*/
|
||||
suspend inline fun alsoWithUnlockingOnSuccess(
|
||||
vararg lockers: SmartRWLocker,
|
||||
block: suspend () -> Unit
|
||||
@@ -14,6 +22,15 @@ suspend inline fun alsoWithUnlockingOnSuccess(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously executes the given [block] and unlocks all provided [lockers] for writing if the block succeeds.
|
||||
* This function launches a new coroutine in the given [scope] and automatically logs and drops any exceptions.
|
||||
*
|
||||
* @param scope The [CoroutineScope] in which to launch the coroutine
|
||||
* @param lockers Variable number of [SmartRWLocker] instances to unlock on successful execution
|
||||
* @param block The suspending function to execute
|
||||
* @return A [Job] representing the launched coroutine
|
||||
*/
|
||||
fun alsoWithUnlockingOnSuccessAsync(
|
||||
scope: CoroutineScope,
|
||||
vararg lockers: SmartRWLocker,
|
||||
|
||||
@@ -3,19 +3,49 @@ package dev.inmo.micro_utils.coroutines
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* Creates a [SupervisorJob] linked to this [CoroutineContext]'s job. The new supervisor job will be a child
|
||||
* of the current job, and optionally combined with [additionalContext].
|
||||
*
|
||||
* @param additionalContext Optional additional context to combine with the supervisor job
|
||||
* @return A [CoroutineContext] containing the new supervisor job
|
||||
*/
|
||||
fun CoroutineContext.LinkedSupervisorJob(
|
||||
additionalContext: CoroutineContext? = null
|
||||
) = SupervisorJob(job).let { if (additionalContext != null) it + additionalContext else it }
|
||||
|
||||
/**
|
||||
* Creates a [SupervisorJob] linked to this [CoroutineScope]'s job. The new supervisor job will be a child
|
||||
* of the current scope's job, and optionally combined with [additionalContext].
|
||||
*
|
||||
* @param additionalContext Optional additional context to combine with the supervisor job
|
||||
* @return A [CoroutineContext] containing the new supervisor job
|
||||
*/
|
||||
fun CoroutineScope.LinkedSupervisorJob(
|
||||
additionalContext: CoroutineContext? = null
|
||||
) = coroutineContext.LinkedSupervisorJob(additionalContext)
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new [CoroutineScope] with a [SupervisorJob] linked to this [CoroutineContext]'s job.
|
||||
* The new scope's supervisor job will be a child of the current job, and optionally combined with [additionalContext].
|
||||
*
|
||||
* @param additionalContext Optional additional context to combine with the supervisor job
|
||||
* @return A new [CoroutineScope] with a linked supervisor job
|
||||
*/
|
||||
fun CoroutineContext.LinkedSupervisorScope(
|
||||
additionalContext: CoroutineContext? = null
|
||||
) = CoroutineScope(
|
||||
this + LinkedSupervisorJob(additionalContext)
|
||||
)
|
||||
|
||||
/**
|
||||
* Creates a new [CoroutineScope] with a [SupervisorJob] linked to this [CoroutineScope]'s job.
|
||||
* The new scope's supervisor job will be a child of the current scope's job, and optionally combined with [additionalContext].
|
||||
*
|
||||
* @param additionalContext Optional additional context to combine with the supervisor job
|
||||
* @return A new [CoroutineScope] with a linked supervisor job
|
||||
*/
|
||||
fun CoroutineScope.LinkedSupervisorScope(
|
||||
additionalContext: CoroutineContext? = null
|
||||
) = coroutineContext.LinkedSupervisorScope(additionalContext)
|
||||
|
||||
@@ -2,9 +2,22 @@ package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
/**
|
||||
* Convenience property to access [Dispatchers.IO] for I/O-bound operations.
|
||||
* This dispatcher is optimized for offloading blocking I/O tasks to a shared pool of threads.
|
||||
*/
|
||||
val IO
|
||||
get() = Dispatchers.IO
|
||||
|
||||
/**
|
||||
* Executes the given [block] on the IO dispatcher and returns its result.
|
||||
* This is a convenience function for executing I/O-bound operations like reading files,
|
||||
* network requests, or database queries.
|
||||
*
|
||||
* @param T The return type of the block
|
||||
* @param block The suspending function to execute on the IO dispatcher
|
||||
* @return The result of executing the block
|
||||
*/
|
||||
suspend inline fun <T> doInIO(noinline block: suspend CoroutineScope.() -> T) = doIn(
|
||||
IO,
|
||||
block
|
||||
|
||||
@@ -3,6 +3,16 @@ package dev.inmo.micro_utils.coroutines
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
/**
|
||||
* Launches a coroutine in the current thread using [Dispatchers.Unconfined] and blocks until it completes,
|
||||
* returning its result. The coroutine will start execution in the current thread and will continue
|
||||
* in the same thread until the first suspension point.
|
||||
*
|
||||
* @param T The return type of the suspending block
|
||||
* @param block The suspending function to execute in the current thread
|
||||
* @return The result of the suspending block
|
||||
* @throws Throwable if the coroutine throws an exception
|
||||
*/
|
||||
fun <T> launchInCurrentThread(block: suspend CoroutineScope.() -> T): T {
|
||||
val scope = CoroutineScope(Dispatchers.Unconfined)
|
||||
return scope.launchSynchronously(block)
|
||||
|
||||
@@ -2,6 +2,16 @@ package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
/**
|
||||
* Launches a coroutine and blocks the current thread until the coroutine completes, returning its result.
|
||||
* This is useful for bridging between suspending and non-suspending code in JVM environments.
|
||||
* The coroutine is launched with [CoroutineStart.UNDISPATCHED] to start execution immediately.
|
||||
*
|
||||
* @param T The return type of the suspending block
|
||||
* @param block The suspending function to execute synchronously
|
||||
* @return The result of the suspending block
|
||||
* @throws Throwable if the coroutine throws an exception
|
||||
*/
|
||||
fun <T> CoroutineScope.launchSynchronously(block: suspend CoroutineScope.() -> T): T {
|
||||
var result: Result<T>? = null
|
||||
val objectToSynchronize = Object()
|
||||
@@ -22,7 +32,31 @@ fun <T> CoroutineScope.launchSynchronously(block: suspend CoroutineScope.() -> T
|
||||
return result!!.getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a coroutine in a new [CoroutineScope] with [Dispatchers.Default] and blocks the current thread
|
||||
* until the coroutine completes, returning its result.
|
||||
*
|
||||
* @param T The return type of the suspending block
|
||||
* @param block The suspending function to execute synchronously
|
||||
* @return The result of the suspending block
|
||||
* @throws Throwable if the coroutine throws an exception
|
||||
*/
|
||||
fun <T> launchSynchronously(block: suspend CoroutineScope.() -> T): T = CoroutineScope(Dispatchers.Default).launchSynchronously(block)
|
||||
|
||||
/**
|
||||
* Alias for [launchSynchronously]. Launches a coroutine and blocks the current thread until it completes.
|
||||
*
|
||||
* @param T The return type of the suspending block
|
||||
* @param block The suspending function to execute synchronously
|
||||
* @return The result of the suspending block
|
||||
*/
|
||||
fun <T> CoroutineScope.doSynchronously(block: suspend CoroutineScope.() -> T): T = launchSynchronously(block)
|
||||
|
||||
/**
|
||||
* Alias for [launchSynchronously]. Launches a coroutine in a new scope and blocks the current thread until it completes.
|
||||
*
|
||||
* @param T The return type of the suspending block
|
||||
* @param block The suspending function to execute synchronously
|
||||
* @return The result of the suspending block
|
||||
*/
|
||||
fun <T> doSynchronously(block: suspend CoroutineScope.() -> T): T = launchSynchronously(block)
|
||||
|
||||
Reference in New Issue
Block a user