blob: 2078a3cc1ec214a2061f22f6b55402028e8acbe1 [file] [log] [blame]
Roman Elizarovd82b3a92017-06-23 21:52:08 +03001/*
2 * Copyright 2016-2017 JetBrains s.r.o.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package kotlinx.coroutines.experimental
18
Roman Elizarov2adf8bc2018-01-24 20:09:57 +030019import kotlinx.coroutines.experimental.CoroutineStart.*
20import kotlinx.coroutines.experimental.intrinsics.*
Roman Elizarov6640b2b2018-01-17 19:08:55 +030021import kotlin.coroutines.experimental.*
Roman Elizarovd82b3a92017-06-23 21:52:08 +030022
23/**
Roman Elizarov6640b2b2018-01-17 19:08:55 +030024 * Abstract base class for implementation of coroutines in coroutine builders.
Roman Elizarov8b38fa22017-09-27 17:44:31 +030025 *
Roman Elizarov23fb7282018-01-24 23:09:42 +030026 * This class implements completion [Continuation], [Job], and [CoroutineScope] interfaces.
27 * It stores the result of continuation in the state of the job.
28 * This coroutine waits for children coroutines to finish before completing and
29 * is cancelled through an intermediate _cancelling_ state.
30 *
31 * The following methods are available for override:
32 *
33 * * [onStart] is invoked when coroutine is create in not active state and is [started][Job.start].
34 * * [onCancellation] is invoked as soon as coroutine is [cancelled][cancel] (becomes _cancelling_)
35 * or when it completes for any reason.
36 * * [onCompleted] is invoked when coroutine completes with a value.
37 * * [onCompletedExceptionally] in invoked when coroutines completes with exception.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030038 *
Roman Elizarov6640b2b2018-01-17 19:08:55 +030039 * @param parentContext context of the parent coroutine.
40 * @param active when `true` (by default) coroutine is created in _active_ state, when `false` in _new_ state.
41 * See [Job] for details.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030042 */
Roman Elizarov6640b2b2018-01-17 19:08:55 +030043@Suppress("EXPOSED_SUPER_CLASS")
Roman Elizarovd82b3a92017-06-23 21:52:08 +030044public abstract class AbstractCoroutine<in T>(
45 private val parentContext: CoroutineContext,
Roman Elizarov6640b2b2018-01-17 19:08:55 +030046 active: Boolean = true
47) : JobSupport(active), Job, Continuation<T>, CoroutineScope {
Roman Elizarovd82b3a92017-06-23 21:52:08 +030048 @Suppress("LeakingThis")
49 public final override val context: CoroutineContext = parentContext + this
Roman Elizarov9fe5f462018-02-21 19:05:52 +030050 @Deprecated("Replaced with context", replaceWith = ReplaceWith("context"))
Roman Elizarov43e3af72017-07-21 16:01:31 +030051 public final override val coroutineContext: CoroutineContext get() = context
Roman Elizarovd82b3a92017-06-23 21:52:08 +030052
Roman Elizarov6640b2b2018-01-17 19:08:55 +030053 /**
54 * Initializes parent job from the `parentContext` of this coroutine that was passed to it during construction.
55 * It shall be invoked at most once after construction after all other initialization.
56 *
57 * Invocation of this function may cause this coroutine to become cancelled if parent is already cancelled,
58 * in which case it synchronously invokes all the corresponding handlers.
Roman Elizarov23fb7282018-01-24 23:09:42 +030059 * @suppress **This is unstable API and it is subject to change.**
Roman Elizarov6640b2b2018-01-17 19:08:55 +030060 */
Roman Elizarov2adf8bc2018-01-24 20:09:57 +030061 internal fun initParentJob() {
Roman Elizarov6640b2b2018-01-17 19:08:55 +030062 initParentJobInternal(parentContext[Job])
63 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +030064
Roman Elizarov6640b2b2018-01-17 19:08:55 +030065 /**
66 * This function is invoked once when non-active coroutine (constructed with `active` set to `false)
67 * is [started][start].
68 */
69 protected open fun onStart() {}
70
71 internal final override fun onStartInternal() {
72 onStart()
73 }
74
75 /**
76 * This function is invoked once when this coroutine is cancelled or is completed,
77 * similarly to [invokeOnCompletion] with `onCancelling` set to `true`.
78 *
Roman Elizarove89cd682018-04-25 13:03:40 +030079 * The meaning of [cause] parameter:
80 * * Cause is `null` when job has completed normally.
81 * * Cause is an instance of [CancellationException] when job was cancelled _normally_.
82 * **It should not be treated as an error**. In particular, it should not be reported to error logs.
83 * * Otherwise, the job had _failed_.
Roman Elizarov6640b2b2018-01-17 19:08:55 +030084 */
85 protected open fun onCancellation(cause: Throwable?) {}
86
Roman Elizarovebc88662018-01-24 23:58:56 +030087 internal override fun onCancellationInternal(exceptionally: CompletedExceptionally?) {
Roman Elizarov6640b2b2018-01-17 19:08:55 +030088 onCancellation(exceptionally?.cause)
89 }
90
91 /**
92 * This function is invoked once when job is completed normally with the specified [value].
93 */
94 protected open fun onCompleted(value: T) {}
95
96 /**
97 * This function is invoked once when job is completed exceptionally with the specified [exception].
98 */
99 protected open fun onCompletedExceptionally(exception: Throwable) {}
100
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300101 @Suppress("UNCHECKED_CAST")
Roman Elizarovebc88662018-01-24 23:58:56 +0300102 internal override fun onCompletionInternal(state: Any?, mode: Int) {
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300103 if (state is CompletedExceptionally)
Vsevolod Tolstopyatovf5e63ca2018-04-12 19:59:56 +0300104 onCompletedExceptionally(state.cause)
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300105 else
106 onCompleted(state as T)
107 }
108
109 internal open val defaultResumeMode: Int get() = MODE_ATOMIC_DEFAULT
110
111 /**
112 * Completes execution of this coroutine normally with the specified [value].
113 */
114 public final override fun resume(value: T) {
Roman Elizarov4d626de2018-01-11 22:57:28 +0300115 makeCompletingOnce(value, defaultResumeMode)
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300116 }
117
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300118 /**
119 * Completes execution of this with coroutine exceptionally with the specified [exception].
120 */
121 public final override fun resumeWithException(exception: Throwable) {
Roman Elizarov4d626de2018-01-11 22:57:28 +0300122 makeCompletingOnce(CompletedExceptionally(exception), defaultResumeMode)
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300123 }
124
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300125 internal final override fun handleException(exception: Throwable) {
Roman Elizarovd82b3a92017-06-23 21:52:08 +0300126 handleCoroutineException(parentContext, exception)
127 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300128
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300129 internal override fun nameString(): String {
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300130 val coroutineName = context.coroutineName ?: return super.nameString()
131 return "\"$coroutineName\":${super.nameString()}"
132 }
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300133
134 /**
Roman Elizarov23fb7282018-01-24 23:09:42 +0300135 * Starts this coroutine with the given code [block] and [start] strategy.
136 * This function shall be invoked at most once on this coroutine.
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300137 *
138 * First, this function initializes parent job from the `parentContext` of this coroutine that was passed to it
139 * during construction. Second, it starts the coroutine based on [start] parameter:
140 *
141 * * [DEFAULT] uses [startCoroutineCancellable].
142 * * [ATOMIC] uses [startCoroutine].
143 * * [UNDISPATCHED] uses [startCoroutineUndispatched].
144 * * [LAZY] does nothing.
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300145 */
146 public fun start(start: CoroutineStart, block: suspend () -> T) {
147 initParentJob()
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300148 start(block, this)
149 }
150
151 /**
Roman Elizarov23fb7282018-01-24 23:09:42 +0300152 * Starts this coroutine with the given code [block] and [start] strategy.
153 * This function shall be invoked at most once on this coroutine.
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300154 *
155 * First, this function initializes parent job from the `parentContext` of this coroutine that was passed to it
156 * during construction. Second, it starts the coroutine based on [start] parameter:
157 *
158 * * [DEFAULT] uses [startCoroutineCancellable].
159 * * [ATOMIC] uses [startCoroutine].
160 * * [UNDISPATCHED] uses [startCoroutineUndispatched].
161 * * [LAZY] does nothing.
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300162 */
163 public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
164 initParentJob()
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300165 start(block, receiver, this)
166 }
Roman Elizarovdfeba242018-01-24 23:31:22 +0300167
168 // todo: This workaround for KT-21968, should be removed in the future
169 override fun invokeOnCompletion(
170 onCancelling: Boolean,
171 invokeImmediately: Boolean,
172 handler: CompletionHandler
173 ): DisposableHandle =
174 super.invokeOnCompletion(onCancelling, invokeImmediately, handler)
175
176 // todo: This workaround for KT-21968, should be removed in the future
177 override fun cancel(cause: Throwable?) =
178 super.cancel(cause)
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300179}
180