commonMain.AbstractCoroutine.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlinx-coroutines-core
Show all versions of kotlinx-coroutines-core
Coroutines support libraries for Kotlin
/*
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")
package kotlinx.coroutines
import kotlinx.coroutines.CoroutineStart.*
import kotlinx.coroutines.intrinsics.*
import kotlin.coroutines.*
/**
* Abstract base class for implementation of coroutines in coroutine builders.
*
* This class implements completion [Continuation], [Job], and [CoroutineScope] interfaces.
* It stores the result of continuation in the state of the job.
* This coroutine waits for children coroutines to finish before completing and
* fails through an intermediate _failing_ state.
*
* The following methods are available for override:
*
* * [onStart] is invoked when the coroutine was created in non-active state and is being [started][Job.start].
* * [onCancelling] is invoked as soon as the coroutine starts being cancelled for any reason (or completes).
* * [onCompleted] is invoked when the coroutine completes with a value.
* * [onCancelled] in invoked when the coroutine completes with an exception (cancelled).
*
* @param parentContext the context of the parent coroutine.
* @param initParentJob specifies whether the parent-child relationship should be instantiated directly
* in `AbstractCoroutine` constructor. If set to `false`, it's the responsibility of the child class
* to invoke [initParentJob] manually.
* @param active when `true` (by default), the coroutine is created in the _active_ state, otherwise it is created in the _new_ state.
* See [Job] for details.
*
* @suppress **This an internal API and should not be used from general code.**
*/
@InternalCoroutinesApi
public abstract class AbstractCoroutine(
parentContext: CoroutineContext,
initParentJob: Boolean,
active: Boolean
) : JobSupport(active), Job, Continuation, CoroutineScope {
init {
/*
* Setup parent-child relationship between the parent in the context and the current coroutine.
* It may cause this coroutine to become _cancelling_ if the parent is already cancelled.
* It is dangerous to install parent-child relationship here if the coroutine class
* operates its state from within onCancelled or onCancelling
* (with exceptions for rx integrations that can't have any parent)
*/
if (initParentJob) initParentJob(parentContext[Job])
}
/**
* The context of this coroutine that includes this coroutine as a [Job].
*/
@Suppress("LeakingThis")
public final override val context: CoroutineContext = parentContext + this
/**
* The context of this scope which is the same as the [context] of this coroutine.
*/
public override val coroutineContext: CoroutineContext get() = context
override val isActive: Boolean get() = super.isActive
/**
* This function is invoked once when the job was completed normally with the specified [value],
* right before all the waiters for the coroutine's completion are notified.
*/
protected open fun onCompleted(value: T) {}
/**
* This function is invoked once when the job was cancelled with the specified [cause],
* right before all the waiters for coroutine's completion are notified.
*
* **Note:** the state of the coroutine might not be final yet in this function and should not be queried.
* You can use [completionCause] and [completionCauseHandled] to recover parameters that we passed
* to this `onCancelled` invocation only when [isCompleted] returns `true`.
*
* @param cause The cancellation (failure) cause
* @param handled `true` if the exception was handled by parent (always `true` when it is a [CancellationException])
*/
protected open fun onCancelled(cause: Throwable, handled: Boolean) {}
override fun cancellationExceptionMessage(): String = "$classSimpleName was cancelled"
@Suppress("UNCHECKED_CAST")
protected final override fun onCompletionInternal(state: Any?) {
if (state is CompletedExceptionally)
onCancelled(state.cause, state.handled)
else
onCompleted(state as T)
}
/**
* Completes execution of this with coroutine with the specified result.
*/
public final override fun resumeWith(result: Result) {
val state = makeCompletingOnce(result.toState())
if (state === COMPLETING_WAITING_CHILDREN) return
afterResume(state)
}
protected open fun afterResume(state: Any?): Unit = afterCompletion(state)
internal final override fun handleOnCompletionException(exception: Throwable) {
handleCoroutineException(context, exception)
}
internal override fun nameString(): String {
val coroutineName = context.coroutineName ?: return super.nameString()
return "\"$coroutineName\":${super.nameString()}"
}
/**
* Starts this coroutine with the given code [block] and [start] strategy.
* This function shall be invoked at most once on this coroutine.
*
* * [DEFAULT] uses [startCoroutineCancellable].
* * [ATOMIC] uses [startCoroutine].
* * [UNDISPATCHED] uses [startCoroutineUndispatched].
* * [LAZY] does nothing.
*/
public fun start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
start(block, receiver, this)
}
}