Added coroutines stdlib classes
This commit is contained in:
@@ -0,0 +1,118 @@
|
|||||||
|
package konan.internal
|
||||||
|
|
||||||
|
import kotlin.coroutines.experimental.*
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.*
|
||||||
|
|
||||||
|
// Single-threaded continuation.
|
||||||
|
class SafeContinuation<in T>
|
||||||
|
constructor(
|
||||||
|
private val delegate: Continuation<T>,
|
||||||
|
initialResult: Any?
|
||||||
|
) : Continuation<T> {
|
||||||
|
|
||||||
|
constructor(delegate: Continuation<T>) : this(delegate, UNDECIDED)
|
||||||
|
|
||||||
|
public override val context: CoroutineContext
|
||||||
|
get() = delegate.context
|
||||||
|
|
||||||
|
private var result: Any? = initialResult
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val UNDECIDED: Any? = Any()
|
||||||
|
private val RESUMED: Any? = Any()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Fail(val exception: Throwable)
|
||||||
|
|
||||||
|
override fun resume(value: T) {
|
||||||
|
when {
|
||||||
|
result === UNDECIDED -> result = value
|
||||||
|
result === COROUTINE_SUSPENDED -> {
|
||||||
|
result = RESUMED
|
||||||
|
delegate.resume(value)
|
||||||
|
}
|
||||||
|
else -> throw IllegalStateException("Already resumed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resumeWithException(exception: Throwable) {
|
||||||
|
when {
|
||||||
|
result === UNDECIDED -> result = Fail(exception)
|
||||||
|
result === COROUTINE_SUSPENDED -> {
|
||||||
|
result = RESUMED
|
||||||
|
delegate.resumeWithException(exception)
|
||||||
|
}
|
||||||
|
else -> throw IllegalStateException("Already resumed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getResult(): Any? {
|
||||||
|
if (this.result === UNDECIDED) this.result = COROUTINE_SUSPENDED
|
||||||
|
val result = this.result
|
||||||
|
when {
|
||||||
|
result === RESUMED -> return COROUTINE_SUSPENDED // already called continuation, indicate COROUTINE_SUSPENDED upstream
|
||||||
|
result is Fail -> throw result.exception
|
||||||
|
else -> return result // either COROUTINE_SUSPENDED or data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExportForCompiler
|
||||||
|
internal fun <T> interceptContinuationIfNeeded(
|
||||||
|
context: CoroutineContext,
|
||||||
|
continuation: Continuation<T>
|
||||||
|
) = context[ContinuationInterceptor]?.interceptContinuation(continuation) ?: continuation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
@ExportForCompiler
|
||||||
|
internal fun <T> normalizeContinuation(continuation: Continuation<T>): Continuation<T> =
|
||||||
|
(continuation as? CoroutineImpl)?.facade ?: continuation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
*/
|
||||||
|
@ExportForCompiler
|
||||||
|
abstract internal class CoroutineImpl(
|
||||||
|
protected var completion: Continuation<Any?>?
|
||||||
|
) : 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
|
||||||
|
protected var label: Int = if (completion != null) 0L else -1L
|
||||||
|
|
||||||
|
private val _context: CoroutineContext? = completion?.context
|
||||||
|
|
||||||
|
override val context: CoroutineContext
|
||||||
|
get() = _context!!
|
||||||
|
|
||||||
|
private var _facade: Continuation<Any?>? = null
|
||||||
|
|
||||||
|
val facade: Continuation<Any?> get() {
|
||||||
|
if (_facade == null) _facade = interceptContinuationIfNeeded(_context!!, this)
|
||||||
|
return _facade!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resume(value: Any?) {
|
||||||
|
processBareContinuationResume(completion!!) {
|
||||||
|
doResume(value, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resumeWithException(exception: Throwable) {
|
||||||
|
processBareContinuationResume(completion!!) {
|
||||||
|
doResume(null, exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun doResume(data: Any?, exception: Throwable?): Any?
|
||||||
|
|
||||||
|
open fun create(completion: Continuation<*>): Continuation<Unit> {
|
||||||
|
throw IllegalStateException("create(Continuation) has not been overridden")
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun create(value: Any?, completion: Continuation<*>): Continuation<Unit> {
|
||||||
|
throw IllegalStateException("create(Any?;Continuation) has not been overridden")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.experimental
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks coroutine context element that intercepts coroutine continuations.
|
||||||
|
* The coroutines framework uses [ContinuationInterceptor.Key] to retrieve the interceptor and
|
||||||
|
* intercepts all coroutine continuations with [interceptContinuation] invocations.
|
||||||
|
*/
|
||||||
|
public interface ContinuationInterceptor : CoroutineContext.Element {
|
||||||
|
/**
|
||||||
|
* The key that defines *the* context interceptor.
|
||||||
|
*/
|
||||||
|
companion object Key : CoroutineContext.Key<ContinuationInterceptor>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns continuation that wraps the original [continuation], thus intercepting all resumptions.
|
||||||
|
* This function is invoked by coroutines framework when needed and the resulting continuations are
|
||||||
|
* cached internally per each instance of the original [continuation].
|
||||||
|
*
|
||||||
|
* By convention, implementations that install themselves as *the* interceptor in the context with
|
||||||
|
* the [Key] shall also scan the context for other element that implement [ContinuationInterceptor] interface
|
||||||
|
* and use their [interceptContinuation] functions, too.
|
||||||
|
*/
|
||||||
|
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.experimental
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persistent context for the coroutine. It is an indexed set of [Element] instances.
|
||||||
|
* An indexed set is a mix between a set and a map.
|
||||||
|
* Every element in this set has a unique [Key]. Keys are compared _by reference_.
|
||||||
|
*/
|
||||||
|
public interface CoroutineContext {
|
||||||
|
/**
|
||||||
|
* Returns the element with the given [key] from this context or `null`.
|
||||||
|
* Keys are compared _by reference_, that is to get an element from the context the reference to its actual key
|
||||||
|
* object must be presented to this function.
|
||||||
|
*/
|
||||||
|
public operator fun <E : Element> get(key: Key<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, Element) -> 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]. Keys are compared _by reference_, that is to remove an element from the context
|
||||||
|
* the reference to its actual key object must be presented to this function.
|
||||||
|
*/
|
||||||
|
public fun minusKey(key: Key<*>): CoroutineContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An element of the [CoroutineContext]. An element of the coroutine context is a singleton context by itself.
|
||||||
|
*/
|
||||||
|
public interface Element : CoroutineContext {
|
||||||
|
/**
|
||||||
|
* A key of this coroutine context element.
|
||||||
|
*/
|
||||||
|
public val key: Key<*>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key for the elements of [CoroutineContext]. [E] is a type of element with this key.
|
||||||
|
* Keys in the context are compared _by reference_.
|
||||||
|
*/
|
||||||
|
public interface Key<E : Element>
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.experimental
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface representing a continuation after a suspension point that returns value of type `T`.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
public fun resume(value: T)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resumes the execution of the corresponding coroutine so that the [exception] is re-thrown right after the
|
||||||
|
* last suspension point.
|
||||||
|
*/
|
||||||
|
public fun resumeWithException(exception: Throwable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* receiver only and are restricted from calling arbitrary suspension functions.
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
public annotation class RestrictsSuspension
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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.experimental
|
||||||
|
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.createCoroutineUnchecked
|
||||||
|
import konan.internal.SafeContinuation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts coroutine with receiver type [R] and result type [T].
|
||||||
|
* This function creates and start a new, fresh instance of suspendable computation every time it is invoked.
|
||||||
|
* The [completion] continuation is invoked when coroutine completes with result or exception.
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
public fun <R, T> (suspend R.() -> T).startCoroutine(
|
||||||
|
receiver: R,
|
||||||
|
completion: Continuation<T>
|
||||||
|
) {
|
||||||
|
createCoroutineUnchecked(receiver, completion).resume(Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts coroutine without receiver and with result type [T].
|
||||||
|
* This function creates and start a new, fresh instance of suspendable computation every time it is invoked.
|
||||||
|
* The [completion] continuation is invoked when coroutine completes with result or exception.
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
public fun <T> (suspend () -> T).startCoroutine(
|
||||||
|
completion: Continuation<T>
|
||||||
|
) {
|
||||||
|
createCoroutineUnchecked(completion).resume(Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a coroutine with receiver type [R] and result type [T].
|
||||||
|
* This function creates a new, fresh instance of suspendable computation every time it is invoked.
|
||||||
|
*
|
||||||
|
* To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
|
||||||
|
* The [completion] continuation is invoked when coroutine completes with result or exception.
|
||||||
|
* Repeated invocation of any resume function on the resulting continuation produces [IllegalStateException].
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
public fun <R, T> (suspend R.() -> T).createCoroutine(
|
||||||
|
receiver: R,
|
||||||
|
completion: Continuation<T>
|
||||||
|
): Continuation<Unit> = SafeContinuation(createCoroutineUnchecked(receiver, completion), COROUTINE_SUSPENDED)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a coroutine without receiver and with result type [T].
|
||||||
|
* This function creates a new, fresh instance of suspendable computation every time it is invoked.
|
||||||
|
*
|
||||||
|
* To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
|
||||||
|
* The [completion] continuation is invoked when coroutine completes with result or exception.
|
||||||
|
* Repeated invocation of any resume function on the resulting continuation produces [IllegalStateException].
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
public fun <T> (suspend () -> T).createCoroutine(
|
||||||
|
completion: Continuation<T>
|
||||||
|
): Continuation<Unit> = SafeContinuation(createCoroutineUnchecked(completion), COROUTINE_SUSPENDED)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the current continuation instance inside suspend functions and suspends
|
||||||
|
* currently running coroutine.
|
||||||
|
*
|
||||||
|
* In this function both [Continuation.resume] and [Continuation.resumeWithException] can be used either synchronously in
|
||||||
|
* the same stack-frame where suspension function is run or asynchronously later in the same thread or
|
||||||
|
* from a different thread of execution. Repeated invocation of any resume function produces [IllegalStateException].
|
||||||
|
*/
|
||||||
|
public inline suspend fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T =
|
||||||
|
suspendCoroutineOrReturn { c: Continuation<T> ->
|
||||||
|
val safe = SafeContinuation(c)
|
||||||
|
block(safe)
|
||||||
|
safe.getResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
// INTERNAL DECLARATIONS
|
||||||
|
|
||||||
|
@kotlin.internal.InlineOnly
|
||||||
|
internal inline fun processBareContinuationResume(completion: Continuation<*>, block: () -> Any?) {
|
||||||
|
try {
|
||||||
|
val result = block()
|
||||||
|
if (result !== COROUTINE_SUSPENDED) {
|
||||||
|
(completion as Continuation<Any?>).resume(result)
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
completion.resumeWithException(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* 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.experimental
|
||||||
|
|
||||||
|
import kotlin.coroutines.experimental.CoroutineContext.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for [CoroutineContext.Element] implementations.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractCoroutineContextElement(public override val key: Key<*>) : Element {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
public override operator fun <E : Element> get(key: Key<E>): E? =
|
||||||
|
if (this.key === key) this as E else null
|
||||||
|
|
||||||
|
public override fun <R> fold(initial: R, operation: (R, Element) -> R): R =
|
||||||
|
operation(initial, this)
|
||||||
|
|
||||||
|
public override operator fun plus(context: CoroutineContext): CoroutineContext =
|
||||||
|
plusImpl(context)
|
||||||
|
|
||||||
|
public override fun minusKey(key: Key<*>): CoroutineContext =
|
||||||
|
if (this.key === key) EmptyCoroutineContext else this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An empty coroutine context.
|
||||||
|
*/
|
||||||
|
public object EmptyCoroutineContext : CoroutineContext {
|
||||||
|
public override fun <E : Element> get(key: Key<E>): E? = null
|
||||||
|
public override fun <R> fold(initial: R, operation: (R, Element) -> R): R = initial
|
||||||
|
public override fun plus(context: CoroutineContext): CoroutineContext = context
|
||||||
|
public override fun minusKey(key: Key<*>): CoroutineContext = this
|
||||||
|
public override fun hashCode(): Int = 0
|
||||||
|
public override fun toString(): String = "EmptyCoroutineContext"
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------- private impl ---------------------
|
||||||
|
|
||||||
|
// this class is not exposed, but is hidden inside implementations
|
||||||
|
// this is a left-biased list, so that `plus` works naturally
|
||||||
|
private class CombinedContext(val left: CoroutineContext, val element: Element) : CoroutineContext {
|
||||||
|
override fun <E : Element> get(key: Key<E>): E? {
|
||||||
|
var cur = this
|
||||||
|
while (true) {
|
||||||
|
cur.element[key]?.let { return it }
|
||||||
|
val next = cur.left
|
||||||
|
if (next is CombinedContext) {
|
||||||
|
cur = next
|
||||||
|
} else {
|
||||||
|
return next[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun <R> fold(initial: R, operation: (R, Element) -> R): R =
|
||||||
|
operation(left.fold(initial, operation), element)
|
||||||
|
|
||||||
|
public override operator fun plus(context: CoroutineContext): CoroutineContext =
|
||||||
|
plusImpl(context)
|
||||||
|
|
||||||
|
public override fun minusKey(key: Key<*>): CoroutineContext {
|
||||||
|
element[key]?.let { return left }
|
||||||
|
val newLeft = left.minusKey(key)
|
||||||
|
return when {
|
||||||
|
newLeft === left -> this
|
||||||
|
newLeft === EmptyCoroutineContext -> element
|
||||||
|
else -> CombinedContext(newLeft, element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun size(): Int =
|
||||||
|
if (left is CombinedContext) left.size() + 1 else 2
|
||||||
|
|
||||||
|
private fun contains(element: Element): Boolean =
|
||||||
|
get(element.key) == element
|
||||||
|
|
||||||
|
private fun containsAll(context: CombinedContext): Boolean {
|
||||||
|
var cur = context
|
||||||
|
while (true) {
|
||||||
|
if (!contains(cur.element)) return false
|
||||||
|
val next = cur.left
|
||||||
|
if (next is CombinedContext) {
|
||||||
|
cur = next
|
||||||
|
} else {
|
||||||
|
return contains(next as Element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
this === other || other is CombinedContext && other.size() == size() && other.containsAll(this)
|
||||||
|
|
||||||
|
override fun hashCode(): Int = left.hashCode() + element.hashCode()
|
||||||
|
|
||||||
|
override fun toString(): String =
|
||||||
|
"[" + fold("") { acc, element ->
|
||||||
|
if (acc.isEmpty()) element.toString() else acc + ", " + element
|
||||||
|
} + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CoroutineContext.plusImpl(context: CoroutineContext): CoroutineContext =
|
||||||
|
if (context === EmptyCoroutineContext) this else // fast path -- avoid lambda creation
|
||||||
|
context.fold(this) { acc, element ->
|
||||||
|
val removed = acc.minusKey(element.key)
|
||||||
|
if (removed === EmptyCoroutineContext) element else {
|
||||||
|
// make sure interceptor is always last in the context (and thus is fast to get when present)
|
||||||
|
val interceptor = removed[ContinuationInterceptor]
|
||||||
|
if (interceptor == null) CombinedContext(removed, element) else {
|
||||||
|
val left = removed.minusKey(ContinuationInterceptor)
|
||||||
|
if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else
|
||||||
|
CombinedContext(CombinedContext(left, element), interceptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* 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.experimental.intrinsics
|
||||||
|
|
||||||
|
import kotlin.coroutines.experimental.Continuation
|
||||||
|
import kotlin.coroutines.experimental.CoroutineContext
|
||||||
|
import kotlin.coroutines.experimental.processBareContinuationResume
|
||||||
|
import konan.internal.interceptContinuationIfNeeded
|
||||||
|
import konan.internal.CoroutineImpl
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the current continuation instance inside suspend functions and either suspend
|
||||||
|
* currently running coroutine or return result immediately without suspension.
|
||||||
|
*
|
||||||
|
* If the [block] returns the special [COROUTINE_SUSPENDED] value, it means that suspend function did suspend the execution and will
|
||||||
|
* not return any result immediately. In this case, the [Continuation] provided to the [block] shall be invoked at some moment in the
|
||||||
|
* future when the result becomes available to resume the computation.
|
||||||
|
*
|
||||||
|
* Otherwise, the return value of the [block] must have a type assignable to [T] and represents the result of this suspend function.
|
||||||
|
* It means that the execution was not suspended and the [Continuation] provided to the [block] shall not be invoked.
|
||||||
|
* As the result type of the [block] is declared as `Any?` and cannot be correctly type-checked,
|
||||||
|
* its proper return type remains on the conscience of the suspend function's author.
|
||||||
|
*
|
||||||
|
* Note that it is not recommended to call either [Continuation.resume] nor [Continuation.resumeWithException] functions synchronously
|
||||||
|
* in the same stackframe where suspension function is run. Use [suspendCoroutine] as a safer way to obtain current
|
||||||
|
* continuation instance.
|
||||||
|
*/
|
||||||
|
@kotlin.internal.InlineOnly
|
||||||
|
public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T = throw Error("Should've been intrinsified")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value is used as a return value of [suspendCoroutineOrReturn] `block` argument to state that
|
||||||
|
* the execution was suspended and will not return any result immediately.
|
||||||
|
*/
|
||||||
|
public val COROUTINE_SUSPENDED: Any = Any()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a coroutine without receiver and with result type [T].
|
||||||
|
* This function creates a new, fresh instance of suspendable computation every time it is invoked.
|
||||||
|
*
|
||||||
|
* To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
|
||||||
|
* The [completion] continuation is invoked when coroutine completes with result or exception.
|
||||||
|
*
|
||||||
|
* This function is _unchecked_. Repeated invocation of any resume function on the resulting continuation corrupts the
|
||||||
|
* state machine of the coroutine and may result in arbitrary behaviour or exception.
|
||||||
|
*/
|
||||||
|
public fun <T> (suspend () -> T).createCoroutineUnchecked(
|
||||||
|
completion: Continuation<T>
|
||||||
|
): Continuation<Unit> =
|
||||||
|
if (this !is CoroutineImpl)
|
||||||
|
buildContinuationByInvokeCall(completion) {
|
||||||
|
(this as Function1<Continuation<T>, Any?>).invoke(completion)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
(this.create(completion) as CoroutineImpl).facade
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a coroutine with receiver type [R] and result type [T].
|
||||||
|
* This function creates a new, fresh instance of suspendable computation every time it is invoked.
|
||||||
|
*
|
||||||
|
* To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
|
||||||
|
* The [completion] continuation is invoked when coroutine completes with result or exception.
|
||||||
|
*
|
||||||
|
* This function is _unchecked_. Repeated invocation of any resume function on the resulting continuation corrupts the
|
||||||
|
* state machine of the coroutine and may result in arbitrary behaviour or exception.
|
||||||
|
*/
|
||||||
|
public fun <R, T> (suspend R.() -> T).createCoroutineUnchecked(
|
||||||
|
receiver: R,
|
||||||
|
completion: Continuation<T>
|
||||||
|
): Continuation<Unit> =
|
||||||
|
if (this !is CoroutineImpl)
|
||||||
|
buildContinuationByInvokeCall(completion) {
|
||||||
|
(this as Function2<R, Continuation<T>, Any?>).invoke(receiver, completion)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
(this.create(receiver, completion) as CoroutineImpl).facade
|
||||||
|
|
||||||
|
// INTERNAL DEFINITIONS
|
||||||
|
private inline fun <T> buildContinuationByInvokeCall(
|
||||||
|
completion: Continuation<T>,
|
||||||
|
crossinline block: () -> Any?
|
||||||
|
): Continuation<Unit> {
|
||||||
|
val continuation =
|
||||||
|
object : Continuation<Unit> {
|
||||||
|
override val context: CoroutineContext
|
||||||
|
get() = completion.context
|
||||||
|
|
||||||
|
override fun resume(value: Unit) {
|
||||||
|
processBareContinuationResume(completion, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resumeWithException(exception: Throwable) {
|
||||||
|
completion.resumeWithException(exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return interceptContinuationIfNeeded(completion.context, continuation)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts unintercepted coroutine without receiver and with result type [T] and executes it until its first suspension.
|
||||||
|
* Returns the result of the coroutine or throws its exception if it does not suspend or [COROUTINE_SUSPENDED] if it suspends.
|
||||||
|
* In the later case, the [completion] continuation is invoked when coroutine completes with result or exception.
|
||||||
|
* This function is designed to be used from inside of [suspendCoroutineOrReturn] to resume the execution of suspended
|
||||||
|
* coroutine using a reference to the suspending function.
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
@kotlin.internal.InlineOnly
|
||||||
|
public inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrReturn(
|
||||||
|
completion: Continuation<T>
|
||||||
|
): Any? = (this as Function1<Continuation<T>, Any?>).invoke(completion)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts unintercepted coroutine with receiver type [R] and result type [T] and executes it until its first suspension.
|
||||||
|
* Returns the result of the coroutine or throws its exception if it does not suspend or [COROUTINE_SUSPENDED] if it suspends.
|
||||||
|
* In the later case, the [completion] continuation is invoked when coroutine completes with result or exception.
|
||||||
|
* This function is designed to be used from inside of [suspendCoroutineOrReturn] to resume the execution of suspended
|
||||||
|
* coroutine using a reference to the suspending function.
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
@kotlin.internal.InlineOnly
|
||||||
|
public inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedOrReturn(
|
||||||
|
receiver: R,
|
||||||
|
completion: Continuation<T>
|
||||||
|
): Any? = (this as Function2<R, Continuation<T>, Any?>).invoke(receiver, completion)
|
||||||
Reference in New Issue
Block a user