Skip to content

Commit

Permalink
Consistent toString for MainCoroutineDispatcher implementations (Kotl…
Browse files Browse the repository at this point in the history
…in#2131)

So that is shows as "Dispatchers.Main" and "Dispatchers.Main.immediate".
Also remove hardcoded "Main" name in places of code where it is not needed anymore.
  • Loading branch information
elizarov authored and recheej committed Dec 28, 2020
1 parent caea252 commit b10c8be
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 17 deletions.
2 changes: 2 additions & 0 deletions kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ public class kotlinx/coroutines/JobSupport : kotlinx/coroutines/ChildJob, kotlin
public abstract class kotlinx/coroutines/MainCoroutineDispatcher : kotlinx/coroutines/CoroutineDispatcher {
public fun <init> ()V
public abstract fun getImmediate ()Lkotlinx/coroutines/MainCoroutineDispatcher;
public fun toString ()Ljava/lang/String;
protected final fun toStringInternalImpl ()Ljava/lang/String;
}

public final class kotlinx/coroutines/NonCancellable : kotlin/coroutines/AbstractCoroutineContextElement, kotlinx/coroutines/Job {
Expand Down
23 changes: 23 additions & 0 deletions kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,27 @@ public abstract class MainCoroutineDispatcher : CoroutineDispatcher() {
* [Dispatchers.Main] supports immediate execution for Android, JavaFx and Swing platforms.
*/
public abstract val immediate: MainCoroutineDispatcher

/**
* Returns a name of this main dispatcher for debugging purposes. This implementation returns
* `Dispatchers.Main` or `Dispatchers.Main.immediate` if it is the same as the corresponding
* reference in [Dispatchers] or a short class-name representation with address otherwise.
*/
override fun toString(): String = toStringInternalImpl() ?: "$classSimpleName@$hexAddress"

/**
* Internal method for more specific [toString] implementations. It returns non-null
* string if this dispatcher is set in the platform as the main one.
* @suppress
*/
@InternalCoroutinesApi
protected fun toStringInternalImpl(): String? {
val main = Dispatchers.Main
if (this === main) return "Dispatchers.Main"
val immediate =
try { main.immediate }
catch (e: UnsupportedOperationException) { null }
if (this === immediate) return "Dispatchers.Main.immediate"
return null
}
}
2 changes: 1 addition & 1 deletion kotlinx-coroutines-core/js/src/Dispatchers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ private class JsMainDispatcher(val delegate: CoroutineDispatcher) : MainCoroutin

override fun dispatchYield(context: CoroutineContext, block: Runnable) = delegate.dispatchYield(context, block)

override fun toString(): String = delegate.toString()
override fun toString(): String = toStringInternalImpl() ?: delegate.toString()
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ private class MissingMainCoroutineDispatcher(
}
}

override fun toString(): String = "Main[missing${if (cause != null) ", cause=$cause" else ""}]"
override fun toString(): String = "Dispatchers.Main[missing${if (cause != null) ", cause=$cause" else ""}]"
}

/**
Expand Down
18 changes: 18 additions & 0 deletions kotlinx-coroutines-core/jvm/test/DispatchersToStringTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.coroutines

import kotlin.test.*

class DispatchersToStringTest {
@Test
fun testStrings() {
assertEquals("Dispatchers.Unconfined", Dispatchers.Unconfined.toString())
assertEquals("Dispatchers.Default", Dispatchers.Default.toString())
assertEquals("Dispatchers.IO", Dispatchers.IO.toString())
assertEquals("Dispatchers.Main[missing]", Dispatchers.Main.toString())
assertEquals("Dispatchers.Main[missing]", Dispatchers.Main.immediate.toString())
}
}
2 changes: 1 addition & 1 deletion kotlinx-coroutines-core/native/src/Dispatchers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ private class NativeMainDispatcher(val delegate: CoroutineDispatcher) : MainCoro

override fun dispatchYield(context: CoroutineContext, block: Runnable) = delegate.dispatchYield(context, block)

override fun toString(): String = delegate.toString()
override fun toString(): String = toStringInternalImpl() ?: delegate.toString()
}
14 changes: 6 additions & 8 deletions ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public sealed class HandlerDispatcher : MainCoroutineDispatcher(), Delay {
internal class AndroidDispatcherFactory : MainDispatcherFactory {

override fun createDispatcher(allFactories: List<MainDispatcherFactory>) =
HandlerContext(Looper.getMainLooper().asHandler(async = true), "Main")
HandlerContext(Looper.getMainLooper().asHandler(async = true))

override fun hintOnError(): String? = "For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used"

Expand Down Expand Up @@ -97,7 +97,7 @@ internal fun Looper.asHandler(async: Boolean): Handler {

@JvmField
@Deprecated("Use Dispatchers.Main instead", level = DeprecationLevel.HIDDEN)
internal val Main: HandlerDispatcher? = runCatching { HandlerContext(Looper.getMainLooper().asHandler(async = true), "Main") }.getOrNull()
internal val Main: HandlerDispatcher? = runCatching { HandlerContext(Looper.getMainLooper().asHandler(async = true)) }.getOrNull()

/**
* Implements [CoroutineDispatcher] on top of an arbitrary Android [Handler].
Expand Down Expand Up @@ -149,12 +149,10 @@ internal class HandlerContext private constructor(
}
}

override fun toString(): String =
if (name != null) {
if (invokeImmediately) "$name [immediate]" else name
} else {
handler.toString()
}
override fun toString(): String = toStringInternalImpl() ?: run {
val str = name ?: handler.toString()
if (invokeImmediately) "$str.immediate" else str
}

override fun equals(other: Any?): Boolean = other is HandlerContext && other.handler === handler
override fun hashCode(): Int = System.identityHashCode(handler)
Expand Down
10 changes: 8 additions & 2 deletions ui/kotlinx-coroutines-android/test/HandlerDispatcherTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ class HandlerDispatcherTest : TestBase() {
ReflectionHelpers.setStaticField(Build.VERSION::class.java, "SDK_INT", 28)
val main = Looper.getMainLooper().asHandler(async = true).asCoroutineDispatcher("testName")
assertEquals("testName", main.toString())
assertEquals("testName [immediate]", main.immediate.toString())
assertEquals("testName [immediate]", main.immediate.immediate.toString())
assertEquals("testName.immediate", main.immediate.toString())
assertEquals("testName.immediate", main.immediate.immediate.toString())
}

private suspend fun Job.join(mainLooper: ShadowLooper) {
Expand Down Expand Up @@ -155,4 +155,10 @@ class HandlerDispatcherTest : TestBase() {
yield() // yield back
finish(5)
}

@Test
fun testMainDispatcherToString() {
assertEquals("Dispatchers.Main", Dispatchers.Main.toString())
assertEquals("Dispatchers.Main.immediate", Dispatchers.Main.immediate.toString())
}
}
4 changes: 2 additions & 2 deletions ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private object ImmediateJavaFxDispatcher : JavaFxDispatcher() {

override fun isDispatchNeeded(context: CoroutineContext): Boolean = !Platform.isFxApplicationThread()

override fun toString() = "JavaFx [immediate]"
override fun toString() = toStringInternalImpl() ?: "JavaFx.immediate"
}

/**
Expand All @@ -85,7 +85,7 @@ internal object JavaFx : JavaFxDispatcher() {
override val immediate: MainCoroutineDispatcher
get() = ImmediateJavaFxDispatcher

override fun toString() = "JavaFx"
override fun toString() = toStringInternalImpl() ?: "JavaFx"
}

private val pulseTimer by lazy {
Expand Down
8 changes: 8 additions & 0 deletions ui/kotlinx-coroutines-javafx/test/JavaFxDispatcherTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package kotlinx.coroutines.javafx
import javafx.application.*
import kotlinx.coroutines.*
import org.junit.*
import org.junit.Test
import kotlin.test.*

class JavaFxDispatcherTest : TestBase() {
@Before
Expand Down Expand Up @@ -56,4 +58,10 @@ class JavaFxDispatcherTest : TestBase() {
finish(5)
}
}

@Test
fun testMainDispatcherToString() {
assertEquals("Dispatchers.Main", Dispatchers.Main.toString())
assertEquals("Dispatchers.Main.immediate", Dispatchers.Main.immediate.toString())
}
}
4 changes: 2 additions & 2 deletions ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private object ImmediateSwingDispatcher : SwingDispatcher() {

override fun isDispatchNeeded(context: CoroutineContext): Boolean = !SwingUtilities.isEventDispatchThread()

override fun toString() = "Swing [immediate]"
override fun toString() = toStringInternalImpl() ?: "Swing.immediate"
}

/**
Expand All @@ -77,5 +77,5 @@ internal object Swing : SwingDispatcher() {
override val immediate: MainCoroutineDispatcher
get() = ImmediateSwingDispatcher

override fun toString() = "Swing"
override fun toString() = toStringInternalImpl() ?: "Swing"
}
6 changes: 6 additions & 0 deletions ui/kotlinx-coroutines-swing/test/SwingTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,10 @@ class SwingTest : TestBase() {
yield() // yield back
finish(5)
}

@Test
fun testMainDispatcherToString() {
assertEquals("Dispatchers.Main", Dispatchers.Main.toString())
assertEquals("Dispatchers.Main.immediate", Dispatchers.Main.immediate.toString())
}
}

0 comments on commit b10c8be

Please sign in to comment.