CoroutineContext and ContinuationInterceptor (instead of dispatcher)
This commit is contained in:
committed by
Denis Zharkov
parent
f611e39a69
commit
8d6a913cee
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlin.coroutines
|
||||
|
||||
/**
|
||||
* Marks coroutine context element that intercepts coroutine continuations.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public interface ContinuationInterceptor : CoroutineContextElement {
|
||||
/**
|
||||
* The key that defines *the* context interceptor.
|
||||
*/
|
||||
companion object : CoroutineContextKey<ContinuationInterceptor>
|
||||
|
||||
/**
|
||||
* Intercepts the given [continuation] by wrapping it. Application code should not call this method directly as
|
||||
* it is invoked by coroutines framework appropriately and the resulting continuations are efficiently cached.
|
||||
*/
|
||||
public fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T>
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlin.coroutines
|
||||
|
||||
/**
|
||||
* Persistent context for the coroutine. It is an indexed set of [CoroutineContextElement] instances.
|
||||
* An indexed set is a mix between a set and a map.
|
||||
* Every element in this set has a unique [CoroutineContextKey].
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public interface CoroutineContext {
|
||||
/**
|
||||
* Returns an element with the given [key] in this context or `null`.
|
||||
*/
|
||||
public operator fun <E : CoroutineContextElement> get(key: CoroutineContextKey<E>): E?
|
||||
|
||||
/**
|
||||
* Accumulates entries of this context starting with [initial] value and applying [operation]
|
||||
* from left to right to current accumulator value and each element of this context.
|
||||
*/
|
||||
public fun <R> fold(initial: R, operation: (R, CoroutineContextElement) -> R): R
|
||||
|
||||
/**
|
||||
* Returns a context containing elements from this context and elements from other [context].
|
||||
* The elements from this context with the same key as in the other one are dropped.
|
||||
*/
|
||||
public operator fun plus(context: CoroutineContext): CoroutineContext
|
||||
|
||||
/**
|
||||
* Returns a context containing elements from this context, but without an element with
|
||||
* the specified [key].
|
||||
*/
|
||||
public fun minusKey(key: CoroutineContextKey<*>): CoroutineContext
|
||||
}
|
||||
|
||||
/**
|
||||
* An element of the [CoroutineContext]. An element of the coroutine context is a singleton context by itself.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public interface CoroutineContextElement : CoroutineContext {
|
||||
/**
|
||||
* A key of this coroutine context element.
|
||||
*/
|
||||
public val contextKey: CoroutineContextKey<*>
|
||||
}
|
||||
|
||||
/**
|
||||
* Key for the elements of [CoroutineContext]. [E] is a type of the element with this key.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public interface CoroutineContextKey<E : CoroutineContextElement>
|
||||
|
||||
@@ -21,6 +21,11 @@ package kotlin.coroutines
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public interface Continuation<in T> {
|
||||
/**
|
||||
* Context of the coroutine that corresponds to this continuation.
|
||||
*/
|
||||
public val context: CoroutineContext
|
||||
|
||||
/**
|
||||
* Resumes the execution of the corresponding coroutine passing [value] as the return value of the last suspension point.
|
||||
*/
|
||||
@@ -33,24 +38,6 @@ public interface Continuation<in T> {
|
||||
public fun resumeWithException(exception: Throwable)
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface to customise dispatch of continuations.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public interface ContinuationDispatcher {
|
||||
/**
|
||||
* Dispatches [Continuation.resume] invocation.
|
||||
* This function must either return `false` or return `true` and invoke `continuation.resume(value)` asynchronously.
|
||||
*/
|
||||
public fun <T> dispatchResume(value: T, continuation: Continuation<T>): Boolean = false
|
||||
|
||||
/**
|
||||
* Dispatches [Continuation.resumeWithException] invocation.
|
||||
* This function must either return `false` or return `true` and invoke `continuation.resumeWithException(exception)` asynchronously.
|
||||
*/
|
||||
public fun dispatchResumeWithException(exception: Throwable, continuation: Continuation<*>): Boolean = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Classes and interfaces marked with this annotation are restricted when used as receivers for extension
|
||||
* `suspend` functions. These `suspend` extensions can only invoke other member or extension `suspend` functions on this particular
|
||||
|
||||
@@ -36,7 +36,7 @@ import kotlin.coroutines.Continuation
|
||||
* continuation instance.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public inline suspend fun <T> suspendCoroutineOrReturn(block: (Continuation<T>) -> Any?): T = null!!
|
||||
public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T = null!!
|
||||
|
||||
/**
|
||||
* This value is used as a return value of [suspendCoroutineOrReturn] `block` argument to state that
|
||||
|
||||
@@ -23,25 +23,23 @@ abstract class CoroutineImpl(
|
||||
arity: Int,
|
||||
@JvmField
|
||||
protected var completion: Continuation<Any?>?
|
||||
) : DispatchedContinuation<Any?>, Lambda(arity), Continuation<Any?> {
|
||||
) : Lambda(arity), Continuation<Any?> {
|
||||
|
||||
// label == -1 when coroutine cannot be started (it is just a factory object) or has already finished execution
|
||||
// label == 0 in initial part of the coroutine
|
||||
@JvmField
|
||||
protected var label: Int = if (completion != null) 0 else -1
|
||||
|
||||
private val _dispatcher: ContinuationDispatcher? = (completion as? DispatchedContinuation<*>)?.dispatcher
|
||||
private val _context: CoroutineContext? = completion?.context
|
||||
|
||||
override val dispatcher: ContinuationDispatcher?
|
||||
get() = _dispatcher
|
||||
override val context: CoroutineContext
|
||||
get() = _context!!
|
||||
|
||||
private var _facade: Continuation<Any?>? = null
|
||||
|
||||
private var facade_: Continuation<Any?>? = null
|
||||
val facade: Continuation<Any?> get() {
|
||||
if (facade_ == null) {
|
||||
facade_ = wrapContinuationIfNeeded(this, dispatcher)
|
||||
}
|
||||
|
||||
return facade_!!
|
||||
if (_facade == null) _facade = _context!![ContinuationInterceptor]?.interceptContinuation(this) ?: this
|
||||
return _facade!!
|
||||
}
|
||||
|
||||
override fun resume(value: Any?) {
|
||||
@@ -66,7 +64,3 @@ abstract class CoroutineImpl(
|
||||
|
||||
protected abstract fun doResume(data: Any?, exception: Throwable?): Any?
|
||||
}
|
||||
|
||||
internal interface DispatchedContinuation<in T> : Continuation<T> {
|
||||
val dispatcher: ContinuationDispatcher?
|
||||
}
|
||||
|
||||
@@ -17,34 +17,6 @@
|
||||
package kotlin.jvm.internal
|
||||
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.ContinuationDispatcher
|
||||
|
||||
fun <T> normalizeContinuation(c: Continuation<T>): Continuation<T> {
|
||||
if (c is CoroutineImpl) {
|
||||
return c.facade
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
internal fun <T> wrapContinuationIfNeeded(c: Continuation<T>, dispatcher: ContinuationDispatcher?): Continuation<T> {
|
||||
if (dispatcher == null) return c
|
||||
return DispatchedContinuationImpl(c, dispatcher)
|
||||
}
|
||||
|
||||
private class DispatchedContinuationImpl<in T>(
|
||||
private val c: Continuation<T>,
|
||||
private val dispatcher: ContinuationDispatcher
|
||||
) : Continuation<T> {
|
||||
override fun resume(value: T) {
|
||||
if (!dispatcher.dispatchResume(value, c)) {
|
||||
c.resume(value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun resumeWithException(exception: Throwable) {
|
||||
if (!dispatcher.dispatchResumeWithException(exception, c)) {
|
||||
c.resumeWithException(exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
fun <T> normalizeContinuation(continuation: Continuation<T>): Continuation<T> =
|
||||
(continuation as? CoroutineImpl)?.facade ?: continuation
|
||||
|
||||
Reference in New Issue
Block a user