@@ -93,17 +93,19 @@ public suspend fun <T> Publisher<T>.awaitSingle(): T = awaitOne(Mode.SINGLE)
93
93
public suspend fun <T > Publisher<T>.awaitSingleOrDefault (default : T ): T = awaitOne(Mode .SINGLE_OR_DEFAULT , default)
94
94
95
95
/* *
96
- * Awaits for the single value from the given publisher or `null` value if none is emitted without blocking a thread and
97
- * returns the resulting value or throws the corresponding exception if this publisher had produced error.
96
+ * Awaits the single value from the given observable without blocking the thread and returns the resulting value, or, if
97
+ * this observable has produced an error, throws the corresponding exception. If more than one value or none were
98
+ * produced by the publisher, `null` is returned.
98
99
*
99
100
* This suspending function is cancellable.
100
- * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
101
- * immediately resumes with [CancellationException].
102
- *
103
- * @throws NoSuchElementException if publisher does not emit any value
104
- * @throws IllegalArgumentException if publisher emits more than one value
101
+ * If the [Job] of the current coroutine is cancelled or completed while the suspending function is waiting, this
102
+ * function immediately cancels its [Subscription] and resumes with [CancellationException].
105
103
*/
106
- public suspend fun <T > Publisher<T>.awaitSingleOrNull (): T = awaitOne(Mode .SINGLE_OR_DEFAULT )
104
+ public suspend fun <T > Publisher<T>.awaitSingleOrNull (): T ? = try {
105
+ awaitOne(Mode .SINGLE_OR_DEFAULT )
106
+ } catch (e: TooManyElementsException ) {
107
+ null
108
+ }
107
109
108
110
/* *
109
111
* 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
@@ -120,6 +122,8 @@ public suspend fun <T> Publisher<T>.awaitSingleOrElse(defaultValue: () -> T): T
120
122
121
123
// ------------------------ private ------------------------
122
124
125
+ private class TooManyElementsException (message : String ): IllegalArgumentException(message)
126
+
123
127
private enum class Mode (val s : String ) {
124
128
FIRST (" awaitFirst" ),
125
129
FIRST_OR_DEFAULT (" awaitFirstOrDefault" ),
@@ -186,7 +190,7 @@ private suspend fun <T> Publisher<T>.awaitOne(
186
190
/* the check for `cont.isActive` is needed in case `sub.cancel() above calls `onComplete` or
187
191
`onError` on its own. */
188
192
if (cont.isActive) {
189
- cont.resumeWithException(IllegalArgumentException (" More than one onNext value for $mode " ))
193
+ cont.resumeWithException(TooManyElementsException (" More than one onNext value for $mode " ))
190
194
}
191
195
} else {
192
196
value = t
0 commit comments