9
9
package kotlinx.coroutines.flow
10
10
11
11
import kotlinx.coroutines.flow.internal.*
12
+ import kotlinx.coroutines.internal.Symbol
12
13
import kotlin.jvm.*
13
14
14
15
/* *
@@ -47,33 +48,39 @@ public suspend inline fun <T, R> Flow<T>.fold(
47
48
}
48
49
49
50
/* *
50
- * The terminal operator, that awaits for one and only one value to be published .
51
+ * The terminal operator that awaits for one and only one value to be emitted .
51
52
* Throws [NoSuchElementException] for empty flow and [IllegalStateException] for flow
52
53
* that contains more than one element.
53
54
*/
54
55
public suspend fun <T > Flow<T>.single (): T {
55
56
var result: Any? = NULL
56
57
collect { value ->
57
- if (result != = NULL ) error( " Expected only one element" )
58
+ require (result == = NULL ) { " Flow has more than one element" }
58
59
result = value
59
60
}
60
61
61
- if (result == = NULL ) throw NoSuchElementException (" Expected at least one element" )
62
- @Suppress(" UNCHECKED_CAST" )
62
+ if (result == = NULL ) throw NoSuchElementException (" Flow is empty" )
63
63
return result as T
64
64
}
65
65
66
66
/* *
67
- * The terminal operator, that awaits for one and only one value to be published .
68
- * Throws [IllegalStateException] for flow that contains more than one element .
67
+ * The terminal operator that awaits for one and only one value to be emitted .
68
+ * Returns the single value or `null`, if the flow was empty or emitted more than one value .
69
69
*/
70
- public suspend fun <T : Any > Flow<T>.singleOrNull (): T ? {
71
- var result: T ? = null
72
- collect { value ->
73
- if (result != null ) error(" Expected only one element" )
74
- result = value
70
+ public suspend fun <T > Flow<T>.singleOrNull (): T ? {
71
+ var result: Any? = NULL
72
+ collectWhile {
73
+ // No values yet, update result
74
+ if (result == = NULL ) {
75
+ result = it
76
+ true
77
+ } else {
78
+ // Second value, reset result and bail out
79
+ result = NULL
80
+ false
81
+ }
75
82
}
76
- return result
83
+ return if ( result == = NULL ) null else result as T
77
84
}
78
85
79
86
/* *
@@ -112,7 +119,7 @@ public suspend fun <T> Flow<T>.first(predicate: suspend (T) -> Boolean): T {
112
119
* The terminal operator that returns the first element emitted by the flow and then cancels flow's collection.
113
120
* Returns `null` if the flow was empty.
114
121
*/
115
- public suspend fun <T : Any > Flow<T>.firstOrNull (): T ? {
122
+ public suspend fun <T > Flow<T>.firstOrNull (): T ? {
116
123
var result: T ? = null
117
124
collectWhile {
118
125
result = it
@@ -122,10 +129,10 @@ public suspend fun <T : Any> Flow<T>.firstOrNull(): T? {
122
129
}
123
130
124
131
/* *
125
- * The terminal operator that returns the first element emitted by the flow matching the given [predicate] and then cancels flow's collection.
132
+ * The terminal operator that returns the first element emitted by the flow matching the given [predicate] and then cancels flow's collection.
126
133
* Returns `null` if the flow did not contain an element matching the [predicate].
127
134
*/
128
- public suspend fun <T : Any > Flow<T>.firstOrNull (predicate : suspend (T ) -> Boolean ): T ? {
135
+ public suspend fun <T > Flow<T>.firstOrNull (predicate : suspend (T ) -> Boolean ): T ? {
129
136
var result: T ? = null
130
137
collectWhile {
131
138
if (predicate(it)) {
0 commit comments