commonMain.flow.terminal.Reduce.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlinx-coroutines-core-js Show documentation
Show all versions of kotlinx-coroutines-core-js Show documentation
Coroutines support libraries for Kotlin
/*
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@file:JvmName("FlowKt")
@file:Suppress("UNCHECKED_CAST")
package kotlinx.coroutines.flow
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.internal.*
import kotlinx.coroutines.flow.internal.unsafeFlow as flow
import kotlin.jvm.*
/**
* Accumulates value starting with the first element and applying [operation] to current accumulator value and each element.
* Throws [NoSuchElementException] if flow was empty.
*/
@ExperimentalCoroutinesApi
public suspend fun Flow.reduce(operation: suspend (accumulator: S, value: T) -> S): S {
var accumulator: Any? = NULL
collect { value ->
accumulator = if (accumulator !== NULL) {
@Suppress("UNCHECKED_CAST")
operation(accumulator as S, value)
} else {
value
}
}
if (accumulator === NULL) throw NoSuchElementException("Empty flow can't be reduced")
@Suppress("UNCHECKED_CAST")
return accumulator as S
}
/**
* Accumulates value starting with [initial] value and applying [operation] current accumulator value and each element
*/
@ExperimentalCoroutinesApi
public suspend inline fun Flow.fold(
initial: R,
crossinline operation: suspend (acc: R, value: T) -> R
): R {
var accumulator = initial
collect { value ->
accumulator = operation(accumulator, value)
}
return accumulator
}
/**
* The terminal operator, that awaits for one and only one value to be published.
* Throws [NoSuchElementException] for empty flow and [IllegalStateException] for flow
* that contains more than one element.
*/
public suspend fun Flow.single(): T {
var result: Any? = NULL
collect { value ->
if (result !== NULL) error("Expected only one element")
result = value
}
if (result === NULL) throw NoSuchElementException("Expected at least one element")
@Suppress("UNCHECKED_CAST")
return result as T
}
/**
* The terminal operator, that awaits for one and only one value to be published.
* Throws [IllegalStateException] for flow that contains more than one element.
*/
public suspend fun Flow.singleOrNull(): T? {
var result: T? = null
collect { value ->
if (result != null) error("Expected only one element")
result = value
}
return result
}
/**
* The terminal operator that returns the first element emitted by the flow and then cancels flow's collection.
* Throws [NoSuchElementException] if the flow was empty.
*/
public suspend fun Flow.first(): T {
var result: Any? = NULL
try {
collect { value ->
result = value
throw AbortFlowException(NopCollector)
}
} catch (e: AbortFlowException) {
// Do nothing
}
if (result === NULL) throw NoSuchElementException("Expected at least one element")
return result as T
}
/**
* The terminal operator that returns the first element emitted by the flow matching the given [predicate] and then cancels flow's collection.
* Throws [NoSuchElementException] if the flow has not contained elements matching the [predicate].
*/
public suspend fun Flow.first(predicate: suspend (T) -> Boolean): T {
var result: Any? = NULL
try {
collect { value ->
if (predicate(value)) {
result = value
throw AbortFlowException(NopCollector)
}
}
} catch (e: AbortFlowException) {
// Do nothing
}
if (result === NULL) throw NoSuchElementException("Expected at least one element matching the predicate $predicate")
return result as T
}
/**
* The terminal operator that returns the first element emitted by the flow and then cancels flow's collection.
* Returns `null` if the flow was empty.
*/
public suspend fun Flow.firstOrNull(): T? {
var result: T? = null
try {
collect { value ->
result = value
throw AbortFlowException(NopCollector)
}
} catch (e: AbortFlowException) {
// Do nothing
}
return result
}
/**
* The terminal operator that returns the first element emitted by the flow matching the given [predicate] and then cancels flow's collection.
* Returns `null` if the flow did not contain an element matching the [predicate].
*/
public suspend fun Flow.firstOrNull(predicate: suspend (T) -> Boolean): T? {
var result: T? = null
try {
collect { value ->
if (predicate(value)) {
result = value
throw AbortFlowException(NopCollector)
}
}
} catch (e: AbortFlowException) {
// Do nothing
}
return result
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy