Skip to content

Commit 731e78e

Browse files
qwwdfsadwoainikk
authored andcommitted
Make trySendBlocking available on K/N (#3064)
Move trySendBlocking from the JVM to the concurrent source-set to make it available on K/N. Fixes #2983
1 parent a4764e5 commit 731e78e

File tree

2 files changed

+23
-60
lines changed

2 files changed

+23
-60
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,13 @@
1-
/*
2-
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3-
*/
4-
51
@file:JvmMultifileClass
62
@file:JvmName("ChannelsKt")
73

84
package kotlinx.coroutines.channels
95

106
import kotlinx.coroutines.*
7+
import kotlin.jvm.*
118

129
/**
13-
* **Deprecated** blocking variant of send.
14-
* This method is deprecated in the favour of [trySendBlocking].
15-
*
16-
* `sendBlocking` is a dangerous primitive — it throws an exception
17-
* if the channel was closed or, more commonly, cancelled.
18-
* Cancellation exceptions in non-blocking code are unexpected and frequently
19-
* trigger internal failures.
20-
*
21-
* These bugs are hard-to-spot during code review and they forced users to write
22-
* their own wrappers around `sendBlocking`.
23-
* So this function is deprecated and replaced with a more explicit primitive.
24-
*
25-
* The real-world example of broken usage with Firebase:
26-
*
27-
* ```kotlin
28-
* callbackFlow {
29-
* val listener = object : ValueEventListener {
30-
* override fun onDataChange(snapshot: DataSnapshot) {
31-
* // This line may fail and crash the app when the downstream flow is cancelled
32-
* sendBlocking(DataSnapshot(snapshot))
33-
* }
34-
*
35-
* override fun onCancelled(error: DatabaseError) {
36-
* close(error.toException())
37-
* }
38-
* }
39-
*
40-
* firebaseQuery.addValueEventListener(listener)
41-
* awaitClose { firebaseQuery.removeEventListener(listener) }
42-
* }
43-
* ```
44-
*/
45-
@Deprecated(
46-
level = DeprecationLevel.ERROR,
47-
message = "Deprecated in the favour of 'trySendBlocking'. " +
48-
"Consider handling the result of 'trySendBlocking' explicitly and rethrow exception if necessary",
49-
replaceWith = ReplaceWith("trySendBlocking(element)")
50-
) // WARNING in 1.5.0, ERROR in 1.6.0, HIDDEN in 1.7.0
51-
public fun <E> SendChannel<E>.sendBlocking(element: E) {
52-
// fast path
53-
if (trySend(element).isSuccess)
54-
return
55-
// slow path
56-
runBlocking {
57-
send(element)
58-
}
59-
}
60-
61-
/**
62-
* Adds [element] into to this channel, **blocking** the caller while this channel is full,
10+
* Adds [element] to this channel, **blocking** the caller while this channel is full,
6311
* and returning either [successful][ChannelResult.isSuccess] result when the element was added, or
6412
* failed result representing closed channel with a corresponding exception.
6513
*
@@ -77,9 +25,8 @@ public fun <E> SendChannel<E>.sendBlocking(element: E) {
7725
*
7826
* For this operation it is guaranteed that [failure][ChannelResult.failed] always contains an exception in it.
7927
*
80-
* @throws [InterruptedException] if the current thread is interrupted during the blocking send operation.
28+
* @throws `InterruptedException` on JVM if the current thread is interrupted during the blocking send operation.
8129
*/
82-
@Throws(InterruptedException::class)
8330
public fun <E> SendChannel<E>.trySendBlocking(element: E): ChannelResult<Unit> {
8431
/*
8532
* Sent successfully -- bail out.
@@ -94,3 +41,20 @@ public fun <E> SendChannel<E>.trySendBlocking(element: E): ChannelResult<Unit> {
9441
else ChannelResult.closed(r.exceptionOrNull())
9542
}
9643
}
44+
45+
/** @suppress */
46+
@Deprecated(
47+
level = DeprecationLevel.ERROR,
48+
message = "Deprecated in the favour of 'trySendBlocking'. " +
49+
"Consider handling the result of 'trySendBlocking' explicitly and rethrow exception if necessary",
50+
replaceWith = ReplaceWith("trySendBlocking(element)")
51+
) // WARNING in 1.5.0, ERROR in 1.6.0, HIDDEN in 1.7.0
52+
public fun <E> SendChannel<E>.sendBlocking(element: E) {
53+
// fast path
54+
if (trySend(element).isSuccess)
55+
return
56+
// slow path
57+
runBlocking {
58+
send(element)
59+
}
60+
}

kotlinx-coroutines-core/jvm/test/channels/ChannelsJvmTest.kt renamed to kotlinx-coroutines-core/concurrent/test/channels/TrySendBlockingTest.kt

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
/*
2-
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.coroutines.channels
66

77
import kotlinx.coroutines.*
8-
import org.junit.Test
98
import kotlin.test.*
109

11-
class ChannelsJvmTest : TestBase() {
10+
class TrySendBlockingTest : TestBase() {
1211

1312
@Test
14-
fun testTrySendBlocking() {
13+
fun testTrySendBlocking() = runBlocking<Unit> { // For old MM
1514
val ch = Channel<Int>()
1615
val sum = GlobalScope.async {
1716
var sum = 0

0 commit comments

Comments
 (0)