• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 @file:Suppress("DEPRECATION_ERROR")
5 
6 package kotlinx.coroutines
7 
8 import kotlinx.coroutines.CoroutineStart.*
9 import kotlinx.coroutines.intrinsics.*
10 import kotlin.coroutines.*
11 
12 /**
13  * Abstract base class for implementation of coroutines in coroutine builders.
14  *
15  * This class implements completion [Continuation], [Job], and [CoroutineScope] interfaces.
16  * It stores the result of continuation in the state of the job.
17  * This coroutine waits for children coroutines to finish before completing and
18  * fails through an intermediate _failing_ state.
19  *
20  * The following methods are available for override:
21  *
22  * * [onStart] is invoked when the coroutine was created in non-active state and is being [started][Job.start].
23  * * [onCancelling] is invoked as soon as the coroutine starts being cancelled for any reason (or completes).
24  * * [onCompleted] is invoked when the coroutine completes with a value.
25  * * [onCancelled] in invoked when the coroutine completes with an exception (cancelled).
26  *
27  * @param parentContext the context of the parent coroutine.
28  * @param initParentJob specifies whether the parent-child relationship should be instantiated directly
29  *               in `AbstractCoroutine` constructor. If set to `false`, it's the responsibility of the child class
30  *               to invoke [initParentJob] manually.
31  * @param active when `true` (by default), the coroutine is created in the _active_ state, otherwise it is created in the _new_ state.
32  *               See [Job] for details.
33  *
34  * @suppress **This an internal API and should not be used from general code.**
35  */
36 @InternalCoroutinesApi
37 public abstract class AbstractCoroutine<in T>(
38     parentContext: CoroutineContext,
39     initParentJob: Boolean,
40     active: Boolean
41 ) : JobSupport(active), Job, Continuation<T>, CoroutineScope {
42 
43     init {
44         /*
45          * Setup parent-child relationship between the parent in the context and the current coroutine.
46          * It may cause this coroutine to become _cancelling_ if the parent is already cancelled.
47          * It is dangerous to install parent-child relationship here if the coroutine class
48          * operates its state from within onCancelled or onCancelling
49          * (with exceptions for rx integrations that can't have any parent)
50          */
51         if (initParentJob) initParentJob(parentContext[Job])
52     }
53 
54     /**
55      * The context of this coroutine that includes this coroutine as a [Job].
56      */
57     @Suppress("LeakingThis")
58     public final override val context: CoroutineContext = parentContext + this
59 
60     /**
61      * The context of this scope which is the same as the [context] of this coroutine.
62      */
63     public override val coroutineContext: CoroutineContext get() = context
64 
65     override val isActive: Boolean get() = super.isActive
66 
67     /**
68      * This function is invoked once when the job was completed normally with the specified [value],
69      * right before all the waiters for the coroutine's completion are notified.
70      */
onCompletednull71     protected open fun onCompleted(value: T) {}
72 
73     /**
74      * This function is invoked once when the job was cancelled with the specified [cause],
75      * right before all the waiters for coroutine's completion are notified.
76      *
77      * **Note:** the state of the coroutine might not be final yet in this function and should not be queried.
78      * You can use [completionCause] and [completionCauseHandled] to recover parameters that we passed
79      * to this `onCancelled` invocation only when [isCompleted] returns `true`.
80      *
81      * @param cause The cancellation (failure) cause
82      * @param handled `true` if the exception was handled by parent (always `true` when it is a [CancellationException])
83      */
onCancellednull84     protected open fun onCancelled(cause: Throwable, handled: Boolean) {}
85 
cancellationExceptionMessagenull86     override fun cancellationExceptionMessage(): String = "$classSimpleName was cancelled"
87 
88     @Suppress("UNCHECKED_CAST")
89     protected final override fun onCompletionInternal(state: Any?) {
90         if (state is CompletedExceptionally)
91             onCancelled(state.cause, state.handled)
92         else
93             onCompleted(state as T)
94     }
95 
96     /**
97      * Completes execution of this with coroutine with the specified result.
98      */
resumeWithnull99     public final override fun resumeWith(result: Result<T>) {
100         val state = makeCompletingOnce(result.toState())
101         if (state === COMPLETING_WAITING_CHILDREN) return
102         afterResume(state)
103     }
104 
afterResumenull105     protected open fun afterResume(state: Any?): Unit = afterCompletion(state)
106 
107     internal final override fun handleOnCompletionException(exception: Throwable) {
108         handleCoroutineException(context, exception)
109     }
110 
nameStringnull111     internal override fun nameString(): String {
112         val coroutineName = context.coroutineName ?: return super.nameString()
113         return "\"$coroutineName\":${super.nameString()}"
114     }
115 
116     /**
117      * Starts this coroutine with the given code [block] and [start] strategy.
118      * This function shall be invoked at most once on this coroutine.
119      *
120      * * [DEFAULT] uses [startCoroutineCancellable].
121      * * [ATOMIC] uses [startCoroutine].
122      * * [UNDISPATCHED] uses [startCoroutineUndispatched].
123      * * [LAZY] does nothing.
124      */
startnull125     public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
126         start(block, receiver, this)
127     }
128 }
129