@@ -3,6 +3,7 @@ package kotlinx.coroutines.experimental
3
3
import java.util.concurrent.atomic.AtomicLong
4
4
import kotlin.coroutines.AbstractCoroutineContextElement
5
5
import kotlin.coroutines.ContinuationInterceptor
6
+ import kotlin.coroutines.ContinuationInterceptor.Key
6
7
import kotlin.coroutines.CoroutineContext
7
8
import kotlin.coroutines.EmptyCoroutineContext
8
9
@@ -23,6 +24,26 @@ public object Here : CoroutineDispatcher() {
23
24
override fun dispatch (block : Runnable ) { throw UnsupportedOperationException () }
24
25
}
25
26
27
+ /* *
28
+ * Returns the context of the coroutine that this function is invoked in or throws
29
+ * [IllegalStateException] if not invoked inside a coroutine.
30
+ * This function can be used to inherit execution context of the parent coroutine if needed,
31
+ * like in `launch(currentCoroutineContext()) { ... }`.
32
+ * This function properly works only for coroutines that are created using [newCoroutineContext] function,
33
+ * as all coroutine builders in `kotlinx.coroutines` do.
34
+ */
35
+ public val currentCoroutineContext: CoroutineContext
36
+ get() = CURRENT_CONTEXT .get() ? : throw IllegalStateException (" Not inside a coroutine" )
37
+
38
+
39
+ /* *
40
+ * Returns the context of the coroutine that this function is invoked in or a specified [default]
41
+ * if not invoked inside a coroutine. A [default] must be a singleton [CoroutineDispatcher] element.
42
+ * See [CoroutineDispatcher] for the standard implementations that are provided by `kotlinx.coroutines`.
43
+ */
44
+ public fun currentCoroutineContextOrDefault (default : CoroutineDispatcher ): CoroutineContext =
45
+ CURRENT_CONTEXT .get() ? : default
46
+
26
47
/* *
27
48
* Creates context for the new coroutine with user-specified overrides from [context] parameter.
28
49
* The [context] for the new coroutine must be explicitly specified and must include [CoroutineDispatcher] element.
@@ -40,16 +61,20 @@ public object Here : CoroutineDispatcher() {
40
61
* The string "coroutine" is used as a default name.
41
62
*/
42
63
public fun newCoroutineContext (context : CoroutineContext ): CoroutineContext {
43
- validateContext(context)
44
- return ((CURRENT_CONTEXT .get() ? : EmptyCoroutineContext ) + context).let {
64
+ val current = CURRENT_CONTEXT .get()
65
+ if (context != = current) {
66
+ check(context[ContinuationInterceptor ] is CoroutineDispatcher ) {
67
+ " Context of new coroutine must include CoroutineDispatcher"
68
+ }
69
+ }
70
+ return ((current ? : EmptyCoroutineContext ) + context).let {
45
71
if (DEBUG ) it + CoroutineId (COROUTINE_ID .incrementAndGet()) else it
46
72
}
47
73
}
48
74
49
75
/* *
50
76
* Executes a block using a given default coroutine context.
51
77
* This context affects all new coroutines that are started withing the block.
52
- * The specified [context] is merged onto the current coroutine context (if any).
53
78
*/
54
79
internal inline fun <T > withDefaultCoroutineContext (context : CoroutineContext , block : () -> T ): T {
55
80
val oldContext = CURRENT_CONTEXT .get()
@@ -61,12 +86,6 @@ internal inline fun <T> withDefaultCoroutineContext(context: CoroutineContext, b
61
86
}
62
87
}
63
88
64
- private fun validateContext (context : CoroutineContext ) {
65
- check(context[ContinuationInterceptor ] is CoroutineDispatcher ) {
66
- " Context of new coroutine must include CoroutineDispatcher"
67
- }
68
- }
69
-
70
89
@PublishedApi
71
90
internal fun updateContext (oldContext : CoroutineContext ? , newContext : CoroutineContext ): String? {
72
91
if (newContext == = oldContext) return null
0 commit comments