Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move trySendBlocking from jvm to concurrent source-set to make it ava… #3064

Merged
merged 2 commits into from
Dec 10, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Move trySendBlocking from jvm to concurrent source-set to make it ava…
…ilable on K/N

Fixes #2983
  • Loading branch information
qwwdfsad committed Dec 6, 2021
commit 85b3526c11caf5cc0bc7b7eeaf1376d5dc4dc050
Original file line number Diff line number Diff line change
@@ -1,65 +1,13 @@
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

@file:JvmMultifileClass
@file:JvmName("ChannelsKt")

package kotlinx.coroutines.channels

import kotlinx.coroutines.*
import kotlin.jvm.*

/**
* **Deprecated** blocking variant of send.
* This method is deprecated in the favour of [trySendBlocking].
*
* `sendBlocking` is a dangerous primitive — it throws an exception
* if the channel was closed or, more commonly, cancelled.
* Cancellation exceptions in non-blocking code are unexpected and frequently
* trigger internal failures.
*
* These bugs are hard-to-spot during code review and they forced users to write
* their own wrappers around `sendBlocking`.
* So this function is deprecated and replaced with a more explicit primitive.
*
* The real-world example of broken usage with Firebase:
*
* ```kotlin
* callbackFlow {
* val listener = object : ValueEventListener {
* override fun onDataChange(snapshot: DataSnapshot) {
* // This line may fail and crash the app when the downstream flow is cancelled
* sendBlocking(DataSnapshot(snapshot))
* }
*
* override fun onCancelled(error: DatabaseError) {
* close(error.toException())
* }
* }
*
* firebaseQuery.addValueEventListener(listener)
* awaitClose { firebaseQuery.removeEventListener(listener) }
* }
* ```
*/
@Deprecated(
level = DeprecationLevel.ERROR,
message = "Deprecated in the favour of 'trySendBlocking'. " +
"Consider handling the result of 'trySendBlocking' explicitly and rethrow exception if necessary",
replaceWith = ReplaceWith("trySendBlocking(element)")
) // WARNING in 1.5.0, ERROR in 1.6.0, HIDDEN in 1.7.0
public fun <E> SendChannel<E>.sendBlocking(element: E) {
// fast path
if (trySend(element).isSuccess)
return
// slow path
runBlocking {
send(element)
}
}

/**
* Adds [element] into to this channel, **blocking** the caller while this channel is full,
* Adds [element] to this channel, **blocking** the caller while this channel is full,
* and returning either [successful][ChannelResult.isSuccess] result when the element was added, or
* failed result representing closed channel with a corresponding exception.
*
Expand All @@ -77,9 +25,8 @@ public fun <E> SendChannel<E>.sendBlocking(element: E) {
*
* For this operation it is guaranteed that [failure][ChannelResult.failed] always contains an exception in it.
*
* @throws [InterruptedException] if the current thread is interrupted during the blocking send operation.
* @throws `InterruptedException` on JVM if the current thread is interrupted during the blocking send operation.
*/
@Throws(InterruptedException::class)
public fun <E> SendChannel<E>.trySendBlocking(element: E): ChannelResult<Unit> {
/*
* Sent successfully -- bail out.
Expand All @@ -94,3 +41,20 @@ public fun <E> SendChannel<E>.trySendBlocking(element: E): ChannelResult<Unit> {
else ChannelResult.closed(r.exceptionOrNull())
}
}

/** @suppress */
@Deprecated(
level = DeprecationLevel.ERROR,
message = "Deprecated in the favour of 'trySendBlocking'. " +
"Consider handling the result of 'trySendBlocking' explicitly and rethrow exception if necessary",
replaceWith = ReplaceWith("trySendBlocking(element)")
) // WARNING in 1.5.0, ERROR in 1.6.0, HIDDEN in 1.7.0
public fun <E> SendChannel<E>.sendBlocking(element: E) {
// fast path
if (trySend(element).isSuccess)
return
// slow path
runBlocking {
send(element)
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.coroutines.channels
package channels
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the IDE messed up here.


import kotlinx.coroutines.*
import org.junit.Test
import kotlinx.coroutines.channels.*
import kotlin.test.*

class ChannelsJvmTest : TestBase() {
class TrySendBlockingTest : TestBase() {

@Test
fun testTrySendBlocking() {
fun testTrySendBlocking() = runBlocking<Unit> { // For old MM
val ch = Channel<Int>()
val sum = GlobalScope.async {
var sum = 0
Expand Down