Skip to content

Commit b10c8be

Browse files
elizarovrecheej
authored andcommitted
Consistent toString for MainCoroutineDispatcher implementations (Kotlin#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.
1 parent caea252 commit b10c8be

File tree

12 files changed

+78
-17
lines changed

12 files changed

+78
-17
lines changed

kotlinx-coroutines-core/api/kotlinx-coroutines-core.api

+2
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,8 @@ public class kotlinx/coroutines/JobSupport : kotlinx/coroutines/ChildJob, kotlin
446446
public abstract class kotlinx/coroutines/MainCoroutineDispatcher : kotlinx/coroutines/CoroutineDispatcher {
447447
public fun <init> ()V
448448
public abstract fun getImmediate ()Lkotlinx/coroutines/MainCoroutineDispatcher;
449+
public fun toString ()Ljava/lang/String;
450+
protected final fun toStringInternalImpl ()Ljava/lang/String;
449451
}
450452

451453
public final class kotlinx/coroutines/NonCancellable : kotlin/coroutines/AbstractCoroutineContextElement, kotlinx/coroutines/Job {

kotlinx-coroutines-core/common/src/MainCoroutineDispatcher.kt

+23
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,27 @@ public abstract class MainCoroutineDispatcher : CoroutineDispatcher() {
4343
* [Dispatchers.Main] supports immediate execution for Android, JavaFx and Swing platforms.
4444
*/
4545
public abstract val immediate: MainCoroutineDispatcher
46+
47+
/**
48+
* Returns a name of this main dispatcher for debugging purposes. This implementation returns
49+
* `Dispatchers.Main` or `Dispatchers.Main.immediate` if it is the same as the corresponding
50+
* reference in [Dispatchers] or a short class-name representation with address otherwise.
51+
*/
52+
override fun toString(): String = toStringInternalImpl() ?: "$classSimpleName@$hexAddress"
53+
54+
/**
55+
* Internal method for more specific [toString] implementations. It returns non-null
56+
* string if this dispatcher is set in the platform as the main one.
57+
* @suppress
58+
*/
59+
@InternalCoroutinesApi
60+
protected fun toStringInternalImpl(): String? {
61+
val main = Dispatchers.Main
62+
if (this === main) return "Dispatchers.Main"
63+
val immediate =
64+
try { main.immediate }
65+
catch (e: UnsupportedOperationException) { null }
66+
if (this === immediate) return "Dispatchers.Main.immediate"
67+
return null
68+
}
4669
}

kotlinx-coroutines-core/js/src/Dispatchers.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ private class JsMainDispatcher(val delegate: CoroutineDispatcher) : MainCoroutin
2626

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

29-
override fun toString(): String = delegate.toString()
29+
override fun toString(): String = toStringInternalImpl() ?: delegate.toString()
3030
}

kotlinx-coroutines-core/jvm/src/internal/MainDispatchers.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ private class MissingMainCoroutineDispatcher(
114114
}
115115
}
116116

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

120120
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.coroutines
6+
7+
import kotlin.test.*
8+
9+
class DispatchersToStringTest {
10+
@Test
11+
fun testStrings() {
12+
assertEquals("Dispatchers.Unconfined", Dispatchers.Unconfined.toString())
13+
assertEquals("Dispatchers.Default", Dispatchers.Default.toString())
14+
assertEquals("Dispatchers.IO", Dispatchers.IO.toString())
15+
assertEquals("Dispatchers.Main[missing]", Dispatchers.Main.toString())
16+
assertEquals("Dispatchers.Main[missing]", Dispatchers.Main.immediate.toString())
17+
}
18+
}

kotlinx-coroutines-core/native/src/Dispatchers.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ private class NativeMainDispatcher(val delegate: CoroutineDispatcher) : MainCoro
2626

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

29-
override fun toString(): String = delegate.toString()
29+
override fun toString(): String = toStringInternalImpl() ?: delegate.toString()
3030
}

ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt

+6-8
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public sealed class HandlerDispatcher : MainCoroutineDispatcher(), Delay {
5252
internal class AndroidDispatcherFactory : MainDispatcherFactory {
5353

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

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

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

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

102102
/**
103103
* Implements [CoroutineDispatcher] on top of an arbitrary Android [Handler].
@@ -149,12 +149,10 @@ internal class HandlerContext private constructor(
149149
}
150150
}
151151

152-
override fun toString(): String =
153-
if (name != null) {
154-
if (invokeImmediately) "$name [immediate]" else name
155-
} else {
156-
handler.toString()
157-
}
152+
override fun toString(): String = toStringInternalImpl() ?: run {
153+
val str = name ?: handler.toString()
154+
if (invokeImmediately) "$str.immediate" else str
155+
}
158156

159157
override fun equals(other: Any?): Boolean = other is HandlerContext && other.handler === handler
160158
override fun hashCode(): Int = System.identityHashCode(handler)

ui/kotlinx-coroutines-android/test/HandlerDispatcherTest.kt

+8-2
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ class HandlerDispatcherTest : TestBase() {
123123
ReflectionHelpers.setStaticField(Build.VERSION::class.java, "SDK_INT", 28)
124124
val main = Looper.getMainLooper().asHandler(async = true).asCoroutineDispatcher("testName")
125125
assertEquals("testName", main.toString())
126-
assertEquals("testName [immediate]", main.immediate.toString())
127-
assertEquals("testName [immediate]", main.immediate.immediate.toString())
126+
assertEquals("testName.immediate", main.immediate.toString())
127+
assertEquals("testName.immediate", main.immediate.immediate.toString())
128128
}
129129

130130
private suspend fun Job.join(mainLooper: ShadowLooper) {
@@ -155,4 +155,10 @@ class HandlerDispatcherTest : TestBase() {
155155
yield() // yield back
156156
finish(5)
157157
}
158+
159+
@Test
160+
fun testMainDispatcherToString() {
161+
assertEquals("Dispatchers.Main", Dispatchers.Main.toString())
162+
assertEquals("Dispatchers.Main.immediate", Dispatchers.Main.immediate.toString())
163+
}
158164
}

ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ private object ImmediateJavaFxDispatcher : JavaFxDispatcher() {
7070

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

73-
override fun toString() = "JavaFx [immediate]"
73+
override fun toString() = toStringInternalImpl() ?: "JavaFx.immediate"
7474
}
7575

7676
/**
@@ -85,7 +85,7 @@ internal object JavaFx : JavaFxDispatcher() {
8585
override val immediate: MainCoroutineDispatcher
8686
get() = ImmediateJavaFxDispatcher
8787

88-
override fun toString() = "JavaFx"
88+
override fun toString() = toStringInternalImpl() ?: "JavaFx"
8989
}
9090

9191
private val pulseTimer by lazy {

ui/kotlinx-coroutines-javafx/test/JavaFxDispatcherTest.kt

+8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package kotlinx.coroutines.javafx
77
import javafx.application.*
88
import kotlinx.coroutines.*
99
import org.junit.*
10+
import org.junit.Test
11+
import kotlin.test.*
1012

1113
class JavaFxDispatcherTest : TestBase() {
1214
@Before
@@ -56,4 +58,10 @@ class JavaFxDispatcherTest : TestBase() {
5658
finish(5)
5759
}
5860
}
61+
62+
@Test
63+
fun testMainDispatcherToString() {
64+
assertEquals("Dispatchers.Main", Dispatchers.Main.toString())
65+
assertEquals("Dispatchers.Main.immediate", Dispatchers.Main.immediate.toString())
66+
}
5967
}

ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ private object ImmediateSwingDispatcher : SwingDispatcher() {
6767

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

70-
override fun toString() = "Swing [immediate]"
70+
override fun toString() = toStringInternalImpl() ?: "Swing.immediate"
7171
}
7272

7373
/**
@@ -77,5 +77,5 @@ internal object Swing : SwingDispatcher() {
7777
override val immediate: MainCoroutineDispatcher
7878
get() = ImmediateSwingDispatcher
7979

80-
override fun toString() = "Swing"
80+
override fun toString() = toStringInternalImpl() ?: "Swing"
8181
}

ui/kotlinx-coroutines-swing/test/SwingTest.kt

+6
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,10 @@ class SwingTest : TestBase() {
9797
yield() // yield back
9898
finish(5)
9999
}
100+
101+
@Test
102+
fun testMainDispatcherToString() {
103+
assertEquals("Dispatchers.Main", Dispatchers.Main.toString())
104+
assertEquals("Dispatchers.Main.immediate", Dispatchers.Main.immediate.toString())
105+
}
100106
}

0 commit comments

Comments
 (0)