Decouple AbstractContinuation and CancellableContinuation from Job interface
diff --git a/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CompletionHandler.kt b/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CompletionHandler.kt
index 0f5cd77..f0a8d52 100644
--- a/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CompletionHandler.kt
+++ b/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CompletionHandler.kt
@@ -23,5 +23,10 @@
actual abstract override fun invoke(cause: Throwable?)
}
+internal actual abstract class CancellationHandler actual constructor() : CompletionHandler {
+ actual inline val asHandler: CompletionHandler get() = this
+ actual abstract override fun invoke(cause: Throwable?)
+}
+
@Suppress("NOTHING_TO_INLINE")
internal actual inline fun CompletionHandler.invokeIt(cause: Throwable?) = invoke(cause)
\ No newline at end of file
diff --git a/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Future.kt b/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Future.kt
index b10f0cd..6909b99 100644
--- a/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Future.kt
+++ b/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Future.kt
@@ -22,15 +22,46 @@
import java.util.concurrent.*
/**
- * Cancels a specified [future] when this job is complete.
- *
+ * Cancels a specified [future] when this job is cancelled.
* This is a shortcut for the following code with slightly more efficient implementation (one fewer object created).
* ```
* invokeOnCompletion { future.cancel(false) }
* ```
*/
public fun Job.cancelFutureOnCompletion(future: Future<*>): DisposableHandle =
- invokeOnCompletion(handler = CancelFutureOnCompletion(this, future))
+ invokeOnCompletion(handler = CancelFutureOnCompletion(this, future)) // TODO make it work only on cancellation as well?
+
+/**
+ * Cancels a specified [future] when this job is cancelled.
+ * This is a shortcut for the following code with slightly more efficient implementation (one fewer object created).
+ * ```
+ * invokeOnCompletion { future.cancel(false) }
+ * ```
+ */
+@Deprecated(
+ message = "Disposable handlers on regular completion are no longer supported",
+ replaceWith = ReplaceWith("cancelFutureOnCancellation(future)"),
+ level = DeprecationLevel.WARNING)
+public fun CancellableContinuation<*>.cancelFutureOnCompletion(future: Future<*>): DisposableHandle {
+ cancelFutureOnCancellation(future)
+ return NonDisposableHandle
+}
+
+/**
+ * Cancels a specified [future] when this job is cancelled.
+ * This is a shortcut for the following code with slightly more efficient implementation (one fewer object created).
+ * ```
+ * invokeOnCancellation { future.cancel(false) }
+ * ```
+ */
+public fun CancellableContinuation<*>.cancelFutureOnCancellation(future: Future<*>) {
+ if (this is AbstractContinuation<*>) {
+ invokeOnCancellation(handler = CancelFutureOnCancellation(this, future))
+ } else {
+ // Fallback if someone else implement CancellableContinuation
+ invokeOnCancellation { future.cancel(false) }
+ }
+}
private class CancelFutureOnCompletion(
job: Job,
@@ -44,3 +75,15 @@
override fun toString() = "CancelFutureOnCompletion[$future]"
}
+private class CancelFutureOnCancellation(
+ continuation: CancellableContinuation<*>,
+ private val future: Future<*>
+) : CancellationHandlerImpl<AbstractContinuation<*>>(continuation as AbstractContinuation<*>) {
+
+ override fun invoke(reason: Throwable?) {
+ // Don't interrupt when cancelling future on completion, because no one is going to reset this
+ // interruption flag and it will cause spurious failures elsewhere
+ future.cancel(false)
+ }
+ override fun toString() = "CancelFutureOnCancellation[$future]"
+}