diff --git a/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api b/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api index 76a0bed462..d86a3d5559 100644 --- a/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api +++ b/kotlinx-coroutines-core/api/kotlinx-coroutines-core.api @@ -151,6 +151,7 @@ public final class kotlinx/coroutines/CoroutineContextKt { } public abstract class kotlinx/coroutines/CoroutineDispatcher : kotlin/coroutines/AbstractCoroutineContextElement, kotlin/coroutines/ContinuationInterceptor { + public static final field Key Lkotlinx/coroutines/CoroutineDispatcher$Key; public fun ()V public abstract fun dispatch (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Runnable;)V public fun dispatchYield (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Runnable;)V @@ -163,6 +164,9 @@ public abstract class kotlinx/coroutines/CoroutineDispatcher : kotlin/coroutines public fun toString ()Ljava/lang/String; } +public final class kotlinx/coroutines/CoroutineDispatcher$Key : kotlin/coroutines/AbstractCoroutineContextKey { +} + public abstract interface class kotlinx/coroutines/CoroutineExceptionHandler : kotlin/coroutines/CoroutineContext$Element { public static final field Key Lkotlinx/coroutines/CoroutineExceptionHandler$Key; public abstract fun handleException (Lkotlin/coroutines/CoroutineContext;Ljava/lang/Throwable;)V @@ -294,11 +298,15 @@ public final class kotlinx/coroutines/ExceptionsKt { } public abstract class kotlinx/coroutines/ExecutorCoroutineDispatcher : kotlinx/coroutines/CoroutineDispatcher, java/io/Closeable { + public static final field Key Lkotlinx/coroutines/ExecutorCoroutineDispatcher$Key; public fun ()V public abstract fun close ()V public abstract fun getExecutor ()Ljava/util/concurrent/Executor; } +public final class kotlinx/coroutines/ExecutorCoroutineDispatcher$Key : kotlin/coroutines/AbstractCoroutineContextKey { +} + public final class kotlinx/coroutines/ExecutorsKt { public static final fun asExecutor (Lkotlinx/coroutines/CoroutineDispatcher;)Ljava/util/concurrent/Executor; public static final fun from (Ljava/util/concurrent/Executor;)Lkotlinx/coroutines/CoroutineDispatcher; diff --git a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt index 3a54390f0b..a618642f72 100644 --- a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt +++ b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt @@ -30,6 +30,12 @@ import kotlin.coroutines.* public abstract class CoroutineDispatcher : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor { + /** @suppress */ + @ExperimentalStdlibApi + public companion object Key : AbstractCoroutineContextKey( + ContinuationInterceptor, + { it as? CoroutineDispatcher }) + /** * Returns `true` if the execution of the coroutine should be performed with [dispatch] method. * The default behavior for most dispatchers is to return `true`. diff --git a/kotlinx-coroutines-core/jvm/src/Executors.kt b/kotlinx-coroutines-core/jvm/src/Executors.kt index e4d25a735e..a4d6b46c43 100644 --- a/kotlinx-coroutines-core/jvm/src/Executors.kt +++ b/kotlinx-coroutines-core/jvm/src/Executors.kt @@ -5,7 +5,7 @@ package kotlinx.coroutines import kotlinx.coroutines.internal.* -import java.io.Closeable +import java.io.* import java.util.concurrent.* import kotlin.coroutines.* @@ -17,17 +17,23 @@ import kotlin.coroutines.* * asynchronous API which requires instance of the [Executor]. */ public abstract class ExecutorCoroutineDispatcher: CoroutineDispatcher(), Closeable { + /** @suppress */ + @ExperimentalStdlibApi + public companion object Key : AbstractCoroutineContextKey( + CoroutineDispatcher, + { it as? ExecutorCoroutineDispatcher }) + + /** + * Underlying executor of current [CoroutineDispatcher]. + */ + public abstract val executor: Executor + /** * Closes this coroutine dispatcher and shuts down its executor. * * It may throw an exception if this dispatcher is global and cannot be closed. */ public abstract override fun close() - - /** - * Underlying executor of current [CoroutineDispatcher]. - */ - public abstract val executor: Executor } /** diff --git a/kotlinx-coroutines-core/jvm/test/DispatcherKeyTest.kt b/kotlinx-coroutines-core/jvm/test/DispatcherKeyTest.kt new file mode 100644 index 0000000000..e2d8ffaa47 --- /dev/null +++ b/kotlinx-coroutines-core/jvm/test/DispatcherKeyTest.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.coroutines + +import org.junit.Test +import kotlin.coroutines.* +import kotlin.test.* + +@UseExperimental(ExperimentalStdlibApi::class) +class DispatcherKeyTest : TestBase() { + + companion object CustomInterceptor : AbstractCoroutineContextElement(ContinuationInterceptor), + ContinuationInterceptor { + override fun interceptContinuation(continuation: Continuation): Continuation { + return continuation + } + } + + private val name = CoroutineName("test") + + @Test + fun testDispatcher() { + val context = name + CustomInterceptor + assertNull(context[CoroutineDispatcher]) + assertSame(CustomInterceptor, context[ContinuationInterceptor]) + + val updated = context + Dispatchers.Main + val result: CoroutineDispatcher? = updated[CoroutineDispatcher] + assertSame(Dispatchers.Main, result) + assertSame(Dispatchers.Main, updated[ContinuationInterceptor]) + assertEquals(name, updated.minusKey(CoroutineDispatcher)) + assertEquals(name, updated.minusKey(ContinuationInterceptor)) + } + + @Test + fun testExecutorCoroutineDispatcher() { + val context = name + CustomInterceptor + assertNull(context[ExecutorCoroutineDispatcher]) + val updated = context + Dispatchers.Main + assertNull(updated[ExecutorCoroutineDispatcher]) + val executor = Dispatchers.Default + val updated2 = updated + executor + assertSame(Dispatchers.Default, updated2[ContinuationInterceptor]) + assertSame(Dispatchers.Default, updated2[CoroutineDispatcher]) + assertSame(Dispatchers.Default as ExecutorCoroutineDispatcher, updated2[ExecutorCoroutineDispatcher]) + assertEquals(name, updated2.minusKey(ContinuationInterceptor)) + assertEquals(name, updated2.minusKey(CoroutineDispatcher)) + assertEquals(name, updated2.minusKey(ExecutorCoroutineDispatcher)) + } +}