blob: 7f23fbda358aa170bdde0a7f826ee2aa56d4cbd5 [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +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
Roman Elizarov3754f952017-01-18 20:47:54 +030017package kotlinx.coroutines.experimental
18
Roman Elizarov23fb7282018-01-24 23:09:42 +030019import kotlinx.coroutines.experimental.intrinsics.*
Roman Elizarov6640b2b2018-01-17 19:08:55 +030020import kotlinx.coroutines.experimental.selects.*
Roman Elizarov2adf8bc2018-01-24 20:09:57 +030021import kotlin.coroutines.experimental.*
Roman Elizarov3754f952017-01-18 20:47:54 +030022
23/**
Roman Elizarov32d95322017-02-09 15:57:31 +030024 * Deferred value is a non-blocking cancellable future.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030025 *
26 * It is created with [async] coroutine builder or via constructor of [CompletableDeferred] class.
Roman Elizarov41c5c8b2017-01-25 13:37:15 +030027 * It is in [active][isActive] state while the value is being computed.
Roman Elizarovb7c46de2017-02-08 12:35:24 +030028 *
Roman Elizarovd82b3a92017-06-23 21:52:08 +030029 * Deferred value has the following states:
Roman Elizarovb7c46de2017-02-08 12:35:24 +030030 *
Roman Elizarovd82b3a92017-06-23 21:52:08 +030031 * | **State** | [isActive] | [isCompleted] | [isCompletedExceptionally] | [isCancelled] |
32 * | --------------------------------------- | ---------- | ------------- | -------------------------- | ------------- |
33 * | _New_ (optional initial state) | `false` | `false` | `false` | `false` |
34 * | _Active_ (default initial state) | `true` | `false` | `false` | `false` |
Roman Elizarov8b38fa22017-09-27 17:44:31 +030035 * | _Completing_ (optional transient state) | `true` | `false` | `false` | `false` |
Roman Elizarovd82b3a92017-06-23 21:52:08 +030036 * | _Cancelling_ (optional transient state) | `false` | `false` | `false` | `true` |
37 * | _Cancelled_ (final state) | `false` | `true` | `true` | `true` |
38 * | _Resolved_ (final state) | `false` | `true` | `false` | `false` |
39 * | _Failed_ (final state) | `false` | `true` | `true` | `false` |
Roman Elizarov32d95322017-02-09 15:57:31 +030040 *
Roman Elizarovd82b3a92017-06-23 21:52:08 +030041 * Usually, a deferred value is created in _active_ state (it is created and started).
Roman Elizarov32d95322017-02-09 15:57:31 +030042 * However, [async] coroutine builder has an optional `start` parameter that creates a deferred value in _new_ state
Roman Elizarovecda27f2017-04-06 23:06:26 +030043 * when this parameter is set to [CoroutineStart.LAZY].
Roman Elizarov32d95322017-02-09 15:57:31 +030044 * Such a deferred can be be made _active_ by invoking [start], [join], or [await].
Roman Elizarovd82b3a92017-06-23 21:52:08 +030045 *
46 * A deferred can be _cancelled_ at any time with [cancel] function that forces it to transition to
Roman Elizarov4d626de2018-01-11 22:57:28 +030047 * _cancelling_ state immediately. Deferred that is not backed by a coroutine (see [CompletableDeferred]) and does not have
48 * [children] becomes _cancelled_ on [cancel] immediately.
49 * Otherwise, deferred becomes _cancelled_ when it finishes executing its code and
50 * when all its children [complete][isCompleted].
Roman Elizarovd82b3a92017-06-23 21:52:08 +030051 *
52 * ```
Roman Elizarov8b38fa22017-09-27 17:44:31 +030053 * wait children
54 * +-----+ start +--------+ complete +-------------+ finish +-----------+
55 * | New | ---------------> | Active | ----------> | Completing | ---+-> | Resolved |
56 * +-----+ +--------+ +-------------+ | |(completed)|
57 * | | | | +-----------+
58 * | cancel | cancel | cancel |
59 * V V | | +-----------+
60 * +-----------+ finish +------------+ | +-> | Failed |
61 * | Cancelled | <--------- | Cancelling | <---------------+ |(completed)|
62 * |(completed)| +------------+ +-----------+
Roman Elizarovd82b3a92017-06-23 21:52:08 +030063 * +-----------+
64 * ```
65 *
Roman Elizarov9fe5f462018-02-21 19:05:52 +030066 * A deferred value is a [Job]. A job in the
67 * [coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html)
68 * of [async] builder represents the coroutine itself.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030069 * A deferred value is active while the coroutine is working and cancellation aborts the coroutine when
70 * the coroutine is suspended on a _cancellable_ suspension point by throwing [CancellationException]
71 * or the cancellation cause inside the coroutine.
72 *
73 * A deferred value can have a _parent_ job. A deferred value with a parent is cancelled when its parent is
Roman Elizarov3e387b82017-12-04 13:49:11 +030074 * cancelled or completes. Parent waits for all its [children] to complete in _completing_ or
Roman Elizarov8b38fa22017-09-27 17:44:31 +030075 * _cancelling_ state. _Completing_ state is purely internal. For an outside observer a _completing_
76 * deferred is still active, while internally it is waiting for its children.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030077 *
78 * All functions on this interface and on all interfaces derived from it are **thread-safe** and can
79 * be safely invoked from concurrent coroutines without external synchronization.
Roman Elizarov3754f952017-01-18 20:47:54 +030080 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +030081public interface Deferred<out T> : Job {
Roman Elizarov3754f952017-01-18 20:47:54 +030082 /**
Roman Elizarovb7c46de2017-02-08 12:35:24 +030083 * Returns `true` if computation of this deferred value has _completed exceptionally_ -- it had
84 * either _failed_ with exception during computation or was [cancelled][cancel].
Roman Elizarov32d95322017-02-09 15:57:31 +030085 *
86 * It implies that [isActive] is `false` and [isCompleted] is `true`.
Roman Elizarovb7c46de2017-02-08 12:35:24 +030087 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +030088 public val isCompletedExceptionally: Boolean
Roman Elizarovb7c46de2017-02-08 12:35:24 +030089
90 /**
Roman Elizarovbe4cae32017-02-15 17:57:02 +030091 * Awaits for completion of this value without blocking a thread and resumes when deferred computation is complete,
92 * returning the resulting value or throwing the corresponding exception if the deferred had completed exceptionally.
Roman Elizarov32d95322017-02-09 15:57:31 +030093 *
Roman Elizarovbe4cae32017-02-15 17:57:02 +030094 * This suspending function is cancellable.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030095 * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
Roman Elizarovc5814542017-01-19 10:19:06 +030096 * immediately resumes with [CancellationException].
Roman Elizarovd84dbc22017-02-22 14:56:58 +030097 *
Roman Elizarovdb0e22d2017-08-29 18:15:57 +030098 * This function can be used in [select] invocation with [onAwait] clause.
Roman Elizarovd84dbc22017-02-22 14:56:58 +030099 * Use [isCompleted] to check for completion of this deferred value without waiting.
Roman Elizarov3754f952017-01-18 20:47:54 +0300100 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300101 public suspend fun await(): T
Roman Elizarovc5814542017-01-19 10:19:06 +0300102
103 /**
Roman Elizarovdb0e22d2017-08-29 18:15:57 +0300104 * Clause for [select] expression of [await] suspending function that selects with the deferred value when it is
105 * resolved. The [select] invocation fails if the deferred value completes exceptionally (either fails or
106 * it cancelled).
Roman Elizarov1216e912017-02-22 09:57:06 +0300107 */
Roman Elizarovdb0e22d2017-08-29 18:15:57 +0300108 public val onAwait: SelectClause1<T>
Roman Elizarov1216e912017-02-22 09:57:06 +0300109
110 /**
Roman Elizarov32d95322017-02-09 15:57:31 +0300111 * Returns *completed* result or throws [IllegalStateException] if this deferred value has not
112 * [completed][isCompleted] yet. It throws the corresponding exception if this deferred has
113 * [completed exceptionally][isCompletedExceptionally].
114 *
Roman Elizarove7803472017-02-16 09:52:31 +0300115 * This function is designed to be used from [invokeOnCompletion] handlers, when there is an absolute certainty that
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300116 * the value is already complete. See also [getCompletionExceptionOrNull].
Roman Elizarovc5814542017-01-19 10:19:06 +0300117 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300118 public fun getCompleted(): T
Roman Elizarov32d95322017-02-09 15:57:31 +0300119
120 /**
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300121 * Returns *completion exception* result if this deferred [completed exceptionally][isCompletedExceptionally],
122 * `null` if it is completed normally, or throws [IllegalStateException] if this deferred value has not
123 * [completed][isCompleted] yet.
124 *
125 * This function is designed to be used from [invokeOnCompletion] handlers, when there is an absolute certainty that
126 * the value is already complete. See also [getCompleted].
127 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300128 public fun getCompletionExceptionOrNull(): Throwable?
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300129
130 /**
Roman Elizarovfc7a9a22017-02-13 11:54:01 +0300131 * @suppress **Deprecated**: Use `isActive`.
Roman Elizarov32d95322017-02-09 15:57:31 +0300132 */
133 @Deprecated(message = "Use `isActive`", replaceWith = ReplaceWith("isActive"))
134 public val isComputing: Boolean get() = isActive
Roman Elizarov3754f952017-01-18 20:47:54 +0300135}
136
137/**
Roman Elizarov32d95322017-02-09 15:57:31 +0300138 * Creates new coroutine and returns its future result as an implementation of [Deferred].
Roman Elizarov44ba4b12017-01-25 11:37:54 +0300139 *
Roman Elizarov32d95322017-02-09 15:57:31 +0300140 * The running coroutine is cancelled when the resulting object is [cancelled][Job.cancel].
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300141 *
142 * The [context] for the new coroutine can be explicitly specified.
143 * See [CoroutineDispatcher] for the standard context implementations that are provided by `kotlinx.coroutines`.
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300144 * The [coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html)
145 * of the parent coroutine may be used,
Roman Elizarov44ba4b12017-01-25 11:37:54 +0300146 * in which case the [Job] of the resulting coroutine is a child of the job of the parent coroutine.
Roman Elizarove8f694e2017-11-28 10:12:00 +0300147 * The parent job may be also explicitly specified using [parent] parameter.
148 *
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300149 * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used.
Roman Elizarov32d95322017-02-09 15:57:31 +0300150 *
Roman Elizarov7b10c942017-05-16 21:02:51 +0300151 * By default, the coroutine is immediately scheduled for execution.
152 * Other options can be specified via `start` parameter. See [CoroutineStart] for details.
Roman Elizarovecda27f2017-04-06 23:06:26 +0300153 * An optional [start] parameter can be set to [CoroutineStart.LAZY] to start coroutine _lazily_. In this case,,
Roman Elizarov32d95322017-02-09 15:57:31 +0300154 * the resulting [Deferred] is created in _new_ state. It can be explicitly started with [start][Job.start]
Vsevolod Tolstopyatovf0ef14e2018-04-11 19:44:08 +0300155 * function and will be started implicitly on the first invocation of [join][Job.join], [await][Deferred.await] or [awaitAll].
Roman Elizarov32d95322017-02-09 15:57:31 +0300156 *
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300157 * @param context context of the coroutine. The default value is [DefaultDispatcher].
158 * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT].
Roman Elizarovfe8ba6b2018-03-13 17:34:29 +0300159 * @param parent explicitly specifies the parent job, overrides job from the [context] (if any).
160 * @param onCompletion optional completion handler for the coroutine (see [Job.invokeOnCompletion]).
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300161 * @param block the coroutine code.
Roman Elizarov3754f952017-01-18 20:47:54 +0300162 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300163public fun <T> async(
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300164 context: CoroutineContext = DefaultDispatcher,
Roman Elizarovecda27f2017-04-06 23:06:26 +0300165 start: CoroutineStart = CoroutineStart.DEFAULT,
Roman Elizarove8f694e2017-11-28 10:12:00 +0300166 parent: Job? = null,
Roman Elizarovfe8ba6b2018-03-13 17:34:29 +0300167 onCompletion: CompletionHandler? = null,
Roman Elizarovecda27f2017-04-06 23:06:26 +0300168 block: suspend CoroutineScope.() -> T
169): Deferred<T> {
Roman Elizarove8f694e2017-11-28 10:12:00 +0300170 val newContext = newCoroutineContext(context, parent)
Roman Elizarovecda27f2017-04-06 23:06:26 +0300171 val coroutine = if (start.isLazy)
172 LazyDeferredCoroutine(newContext, block) else
173 DeferredCoroutine<T>(newContext, active = true)
Roman Elizarovfe8ba6b2018-03-13 17:34:29 +0300174 if (onCompletion != null) coroutine.invokeOnCompletion(handler = onCompletion)
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300175 coroutine.start(start, coroutine, block)
Roman Elizarov32d95322017-02-09 15:57:31 +0300176 return coroutine
177}
178
Roman Elizarove8f694e2017-11-28 10:12:00 +0300179/** @suppress **Deprecated**: Binary compatibility */
180@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
181public fun <T> async(
182 context: CoroutineContext = DefaultDispatcher,
183 start: CoroutineStart = CoroutineStart.DEFAULT,
Roman Elizarovfe8ba6b2018-03-13 17:34:29 +0300184 parent: Job? = null,
185 block: suspend CoroutineScope.() -> T
186): Deferred<T> = async(context, start, parent, block = block)
187
188/** @suppress **Deprecated**: Binary compatibility */
189@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
190public fun <T> async(
191 context: CoroutineContext = DefaultDispatcher,
192 start: CoroutineStart = CoroutineStart.DEFAULT,
Roman Elizarove8f694e2017-11-28 10:12:00 +0300193 block: suspend CoroutineScope.() -> T
194): Deferred<T> =
195 async(context, start, block = block)
196
Roman Elizarov32d95322017-02-09 15:57:31 +0300197/**
Roman Elizarovecda27f2017-04-06 23:06:26 +0300198 * @suppress **Deprecated**: Use `start = CoroutineStart.XXX` parameter
199 */
200@Deprecated(message = "Use `start = CoroutineStart.XXX` parameter",
201 replaceWith = ReplaceWith("async(context, if (start) CoroutineStart.DEFAULT else CoroutineStart.LAZY, block)"))
202public fun <T> async(context: CoroutineContext, start: Boolean, block: suspend CoroutineScope.() -> T): Deferred<T> =
Roman Elizarove8f694e2017-11-28 10:12:00 +0300203 async(context, if (start) CoroutineStart.DEFAULT else CoroutineStart.LAZY, block = block)
Roman Elizarovecda27f2017-04-06 23:06:26 +0300204
205/**
Roman Elizarovfc7a9a22017-02-13 11:54:01 +0300206 * @suppress **Deprecated**: `defer` was renamed to `async`.
Roman Elizarov32d95322017-02-09 15:57:31 +0300207 */
208@Deprecated(message = "`defer` was renamed to `async`", level = DeprecationLevel.WARNING,
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300209 replaceWith = ReplaceWith("async(context, block = block)"))
Roman Elizarovecda27f2017-04-06 23:06:26 +0300210public fun <T> defer(context: CoroutineContext, block: suspend CoroutineScope.() -> T): Deferred<T> =
Roman Elizarov32d95322017-02-09 15:57:31 +0300211 async(context, block = block)
Roman Elizarov3754f952017-01-18 20:47:54 +0300212
Roman Elizarov7a3afb52017-06-19 19:27:08 +0300213@Suppress("UNCHECKED_CAST")
Roman Elizarov32d95322017-02-09 15:57:31 +0300214private open class DeferredCoroutine<T>(
Roman Elizarov2b12d582017-06-22 20:12:19 +0300215 parentContext: CoroutineContext,
Roman Elizarov32d95322017-02-09 15:57:31 +0300216 active: Boolean
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300217) : AbstractCoroutine<T>(parentContext, active), Deferred<T>, SelectClause1<T> {
Roman Elizarov7a3afb52017-06-19 19:27:08 +0300218 override fun getCompleted(): T = getCompletedInternal() as T
Roman Elizarove3f28842017-12-21 19:15:40 +0300219 override suspend fun await(): T = awaitInternal() as T
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300220 override val onAwait: SelectClause1<T> get() = this
221 override fun <R> registerSelectClause1(select: SelectInstance<R>, block: suspend (T) -> R) =
222 registerSelectClause1Internal(select, block)
Roman Elizarov1216e912017-02-22 09:57:06 +0300223}
224
Roman Elizarov32d95322017-02-09 15:57:31 +0300225private class LazyDeferredCoroutine<T>(
Roman Elizarov1216e912017-02-22 09:57:06 +0300226 parentContext: CoroutineContext,
227 private val block: suspend CoroutineScope.() -> T
228) : DeferredCoroutine<T>(parentContext, active = false) {
Roman Elizarov32d95322017-02-09 15:57:31 +0300229 override fun onStart() {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300230 block.startCoroutineCancellable(this, this)
Roman Elizarov32d95322017-02-09 15:57:31 +0300231 }
Roman Elizarov3754f952017-01-18 20:47:54 +0300232}