@@ -94,17 +94,19 @@ public suspend fun <T> Publisher<T>.awaitSingle(): T = awaitOne(Mode.SINGLE)
94
94
public suspend fun <T > Publisher<T>.awaitSingleOrDefault (default : T ): T = awaitOne(Mode .SINGLE_OR_DEFAULT , default)
95
95
96
96
/* *
97
- * Awaits for the single value from the given publisher or `null` value if none is emitted without blocking a thread and
98
- * returns the resulting value or throws the corresponding exception if this publisher had produced error.
97
+ * Awaits the single value from the given observable without blocking the thread and returns the resulting value, or, if
98
+ * this observable has produced an error, throws the corresponding exception. If more than one value or none were
99
+ * produced by the publisher, `null` is returned.
99
100
*
100
101
* This suspending function is cancellable.
101
- * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
102
- * immediately resumes with [CancellationException].
103
- *
104
- * @throws NoSuchElementException if publisher does not emit any value
105
- * @throws IllegalArgumentException if publisher emits more than one value
102
+ * If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
103
+ * function immediately cancels its [Subscription] and resumes with [CancellationException].
106
104
*/
107
- public suspend fun <T > Publisher<T>.awaitSingleOrNull (): T = awaitOne(Mode .SINGLE_OR_DEFAULT )
105
+ public suspend fun <T > Publisher<T>.awaitSingleOrNull (): T ? = try {
106
+ awaitOne(Mode .SINGLE_OR_DEFAULT )
107
+ } catch (e: TooManyElementsException ) {
108
+ null
109
+ }
108
110
109
111
/* *
110
112
* Awaits for the single value from the given publisher or call [defaultValue] to get a value if none is emitted without blocking a thread and
@@ -121,6 +123,8 @@ public suspend fun <T> Publisher<T>.awaitSingleOrElse(defaultValue: () -> T): T
121
123
122
124
// ------------------------ private ------------------------
123
125
126
+ private class TooManyElementsException (message : String ): IllegalArgumentException(message)
127
+
124
128
private enum class Mode (val s : String ) {
125
129
FIRST (" awaitFirst" ),
126
130
FIRST_OR_DEFAULT (" awaitFirstOrDefault" ),
@@ -158,7 +162,7 @@ private suspend fun <T> Publisher<T>.awaitOne(
158
162
if ((mode == Mode .SINGLE || mode == Mode .SINGLE_OR_DEFAULT ) && seenValue) {
159
163
subscription.cancel()
160
164
if (cont.isActive)
161
- cont.resumeWithException(IllegalArgumentException (" More than one onNext value for $mode " ))
165
+ cont.resumeWithException(TooManyElementsException (" More than one onNext value for $mode " ))
162
166
} else {
163
167
value = t
164
168
seenValue = true
0 commit comments