blob: 63960b1bca859623ca822217ccb6856013a595ba [file] [log] [blame]
Roman Elizarovd82b3a92017-06-23 21:52:08 +03001/*
Roman Elizarov1f74a2d2018-06-29 19:19:45 +03002 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
Roman Elizarovd82b3a92017-06-23 21:52:08 +03003 */
4
5package kotlinx.coroutines.experimental
6
Roman Elizarov2adf8bc2018-01-24 20:09:57 +03007import kotlinx.coroutines.experimental.CoroutineStart.*
8import kotlinx.coroutines.experimental.intrinsics.*
Roman Elizarov6640b2b2018-01-17 19:08:55 +03009import kotlin.coroutines.experimental.*
Roman Elizarovd82b3a92017-06-23 21:52:08 +030010
11/**
Roman Elizarov6640b2b2018-01-17 19:08:55 +030012 * Abstract base class for implementation of coroutines in coroutine builders.
Roman Elizarov8b38fa22017-09-27 17:44:31 +030013 *
Roman Elizarov23fb7282018-01-24 23:09:42 +030014 * This class implements completion [Continuation], [Job], and [CoroutineScope] interfaces.
15 * It stores the result of continuation in the state of the job.
16 * This coroutine waits for children coroutines to finish before completing and
17 * is cancelled through an intermediate _cancelling_ state.
18 *
19 * The following methods are available for override:
20 *
21 * * [onStart] is invoked when coroutine is create in not active state and is [started][Job.start].
22 * * [onCancellation] is invoked as soon as coroutine is [cancelled][cancel] (becomes _cancelling_)
23 * or when it completes for any reason.
24 * * [onCompleted] is invoked when coroutine completes with a value.
25 * * [onCompletedExceptionally] in invoked when coroutines completes with exception.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030026 *
Roman Elizarov6640b2b2018-01-17 19:08:55 +030027 * @param parentContext context of the parent coroutine.
28 * @param active when `true` (by default) coroutine is created in _active_ state, when `false` in _new_ state.
29 * See [Job] for details.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030030 */
Roman Elizarov6640b2b2018-01-17 19:08:55 +030031@Suppress("EXPOSED_SUPER_CLASS")
Roman Elizarovd82b3a92017-06-23 21:52:08 +030032public abstract class AbstractCoroutine<in T>(
33 private val parentContext: CoroutineContext,
Roman Elizarov6640b2b2018-01-17 19:08:55 +030034 active: Boolean = true
35) : JobSupport(active), Job, Continuation<T>, CoroutineScope {
Roman Elizarovd82b3a92017-06-23 21:52:08 +030036 @Suppress("LeakingThis")
37 public final override val context: CoroutineContext = parentContext + this
Roman Elizarov9fe5f462018-02-21 19:05:52 +030038 @Deprecated("Replaced with context", replaceWith = ReplaceWith("context"))
Roman Elizarov43e3af72017-07-21 16:01:31 +030039 public final override val coroutineContext: CoroutineContext get() = context
Roman Elizarovd82b3a92017-06-23 21:52:08 +030040
Roman Elizarov6640b2b2018-01-17 19:08:55 +030041 /**
42 * Initializes parent job from the `parentContext` of this coroutine that was passed to it during construction.
43 * It shall be invoked at most once after construction after all other initialization.
44 *
45 * Invocation of this function may cause this coroutine to become cancelled if parent is already cancelled,
46 * in which case it synchronously invokes all the corresponding handlers.
Roman Elizarov23fb7282018-01-24 23:09:42 +030047 * @suppress **This is unstable API and it is subject to change.**
Roman Elizarov6640b2b2018-01-17 19:08:55 +030048 */
Roman Elizarov2adf8bc2018-01-24 20:09:57 +030049 internal fun initParentJob() {
Roman Elizarov6640b2b2018-01-17 19:08:55 +030050 initParentJobInternal(parentContext[Job])
51 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +030052
Roman Elizarov6640b2b2018-01-17 19:08:55 +030053 /**
54 * This function is invoked once when non-active coroutine (constructed with `active` set to `false)
55 * is [started][start].
56 */
57 protected open fun onStart() {}
58
59 internal final override fun onStartInternal() {
60 onStart()
61 }
62
63 /**
64 * This function is invoked once when this coroutine is cancelled or is completed,
65 * similarly to [invokeOnCompletion] with `onCancelling` set to `true`.
66 *
Roman Elizarove89cd682018-04-25 13:03:40 +030067 * The meaning of [cause] parameter:
68 * * Cause is `null` when job has completed normally.
69 * * Cause is an instance of [CancellationException] when job was cancelled _normally_.
70 * **It should not be treated as an error**. In particular, it should not be reported to error logs.
71 * * Otherwise, the job had _failed_.
Roman Elizarov6640b2b2018-01-17 19:08:55 +030072 */
73 protected open fun onCancellation(cause: Throwable?) {}
74
Roman Elizarovebc88662018-01-24 23:58:56 +030075 internal override fun onCancellationInternal(exceptionally: CompletedExceptionally?) {
Roman Elizarov6640b2b2018-01-17 19:08:55 +030076 onCancellation(exceptionally?.cause)
77 }
78
79 /**
80 * This function is invoked once when job is completed normally with the specified [value].
81 */
82 protected open fun onCompleted(value: T) {}
83
84 /**
85 * This function is invoked once when job is completed exceptionally with the specified [exception].
86 */
87 protected open fun onCompletedExceptionally(exception: Throwable) {}
88
Roman Elizarov6640b2b2018-01-17 19:08:55 +030089 @Suppress("UNCHECKED_CAST")
Roman Elizarovebc88662018-01-24 23:58:56 +030090 internal override fun onCompletionInternal(state: Any?, mode: Int) {
Roman Elizarov6640b2b2018-01-17 19:08:55 +030091 if (state is CompletedExceptionally)
Vsevolod Tolstopyatovf5e63ca2018-04-12 19:59:56 +030092 onCompletedExceptionally(state.cause)
Roman Elizarov6640b2b2018-01-17 19:08:55 +030093 else
94 onCompleted(state as T)
95 }
96
97 internal open val defaultResumeMode: Int get() = MODE_ATOMIC_DEFAULT
98
99 /**
100 * Completes execution of this coroutine normally with the specified [value].
101 */
102 public final override fun resume(value: T) {
Roman Elizarov4d626de2018-01-11 22:57:28 +0300103 makeCompletingOnce(value, defaultResumeMode)
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300104 }
105
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300106 /**
107 * Completes execution of this with coroutine exceptionally with the specified [exception].
108 */
109 public final override fun resumeWithException(exception: Throwable) {
Roman Elizarov4d626de2018-01-11 22:57:28 +0300110 makeCompletingOnce(CompletedExceptionally(exception), defaultResumeMode)
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300111 }
112
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300113 internal final override fun handleException(exception: Throwable) {
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300114 handleCoroutineException(parentContext, exception)
115 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300116
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300117 internal override fun nameString(): String {
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300118 val coroutineName = context.coroutineName ?: return super.nameString()
119 return "\"$coroutineName\":${super.nameString()}"
120 }
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300121
122 /**
Roman Elizarov23fb7282018-01-24 23:09:42 +0300123 * Starts this coroutine with the given code [block] and [start] strategy.
124 * This function shall be invoked at most once on this coroutine.
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300125 *
126 * First, this function initializes parent job from the `parentContext` of this coroutine that was passed to it
127 * during construction. Second, it starts the coroutine based on [start] parameter:
128 *
129 * * [DEFAULT] uses [startCoroutineCancellable].
130 * * [ATOMIC] uses [startCoroutine].
131 * * [UNDISPATCHED] uses [startCoroutineUndispatched].
132 * * [LAZY] does nothing.
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300133 */
134 public fun start(start: CoroutineStart, block: suspend () -> T) {
135 initParentJob()
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300136 start(block, this)
137 }
138
139 /**
Roman Elizarov23fb7282018-01-24 23:09:42 +0300140 * Starts this coroutine with the given code [block] and [start] strategy.
141 * This function shall be invoked at most once on this coroutine.
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300142 *
143 * First, this function initializes parent job from the `parentContext` of this coroutine that was passed to it
144 * during construction. Second, it starts the coroutine based on [start] parameter:
145 *
146 * * [DEFAULT] uses [startCoroutineCancellable].
147 * * [ATOMIC] uses [startCoroutine].
148 * * [UNDISPATCHED] uses [startCoroutineUndispatched].
149 * * [LAZY] does nothing.
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300150 */
151 public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
152 initParentJob()
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300153 start(block, receiver, this)
154 }
Roman Elizarovdfeba242018-01-24 23:31:22 +0300155
156 // todo: This workaround for KT-21968, should be removed in the future
157 override fun invokeOnCompletion(
158 onCancelling: Boolean,
159 invokeImmediately: Boolean,
160 handler: CompletionHandler
161 ): DisposableHandle =
162 super.invokeOnCompletion(onCancelling, invokeImmediately, handler)
163
164 // todo: This workaround for KT-21968, should be removed in the future
165 override fun cancel(cause: Throwable?) =
166 super.cancel(cause)
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300167}
168