blob: 1f0bd7fabc593cc187c620fb46f1d4a668397107 [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +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 Elizarovf16fd272017-02-07 11:26:00 +03003 */
4
Roman Elizarov3754f952017-01-18 20:47:54 +03005package kotlinx.coroutines.experimental
6
Roman Elizarov23fb7282018-01-24 23:09:42 +03007import kotlinx.coroutines.experimental.intrinsics.*
Roman Elizarov6640b2b2018-01-17 19:08:55 +03008import kotlinx.coroutines.experimental.selects.*
Roman Elizarov2adf8bc2018-01-24 20:09:57 +03009import kotlin.coroutines.experimental.*
Roman Elizarov3754f952017-01-18 20:47:54 +030010
11/**
Roman Elizarov32d95322017-02-09 15:57:31 +030012 * Deferred value is a non-blocking cancellable future.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030013 *
14 * It is created with [async] coroutine builder or via constructor of [CompletableDeferred] class.
Roman Elizarov41c5c8b2017-01-25 13:37:15 +030015 * It is in [active][isActive] state while the value is being computed.
Roman Elizarovb7c46de2017-02-08 12:35:24 +030016 *
Roman Elizarovd82b3a92017-06-23 21:52:08 +030017 * Deferred value has the following states:
Roman Elizarovb7c46de2017-02-08 12:35:24 +030018 *
Roman Elizarovd82b3a92017-06-23 21:52:08 +030019 * | **State** | [isActive] | [isCompleted] | [isCompletedExceptionally] | [isCancelled] |
20 * | --------------------------------------- | ---------- | ------------- | -------------------------- | ------------- |
21 * | _New_ (optional initial state) | `false` | `false` | `false` | `false` |
22 * | _Active_ (default initial state) | `true` | `false` | `false` | `false` |
Roman Elizarov8b38fa22017-09-27 17:44:31 +030023 * | _Completing_ (optional transient state) | `true` | `false` | `false` | `false` |
Roman Elizarovd82b3a92017-06-23 21:52:08 +030024 * | _Cancelling_ (optional transient state) | `false` | `false` | `false` | `true` |
25 * | _Cancelled_ (final state) | `false` | `true` | `true` | `true` |
26 * | _Resolved_ (final state) | `false` | `true` | `false` | `false` |
27 * | _Failed_ (final state) | `false` | `true` | `true` | `false` |
Roman Elizarov32d95322017-02-09 15:57:31 +030028 *
Roman Elizarovd82b3a92017-06-23 21:52:08 +030029 * Usually, a deferred value is created in _active_ state (it is created and started).
Roman Elizarov32d95322017-02-09 15:57:31 +030030 * However, [async] coroutine builder has an optional `start` parameter that creates a deferred value in _new_ state
Roman Elizarovecda27f2017-04-06 23:06:26 +030031 * when this parameter is set to [CoroutineStart.LAZY].
Roman Elizarov32d95322017-02-09 15:57:31 +030032 * Such a deferred can be be made _active_ by invoking [start], [join], or [await].
Roman Elizarovd82b3a92017-06-23 21:52:08 +030033 *
34 * A deferred can be _cancelled_ at any time with [cancel] function that forces it to transition to
Roman Elizarov4d626de2018-01-11 22:57:28 +030035 * _cancelling_ state immediately. Deferred that is not backed by a coroutine (see [CompletableDeferred]) and does not have
36 * [children] becomes _cancelled_ on [cancel] immediately.
37 * Otherwise, deferred becomes _cancelled_ when it finishes executing its code and
38 * when all its children [complete][isCompleted].
Roman Elizarovd82b3a92017-06-23 21:52:08 +030039 *
40 * ```
Roman Elizarov8b38fa22017-09-27 17:44:31 +030041 * wait children
42 * +-----+ start +--------+ complete +-------------+ finish +-----------+
43 * | New | ---------------> | Active | ----------> | Completing | ---+-> | Resolved |
44 * +-----+ +--------+ +-------------+ | |(completed)|
45 * | | | | +-----------+
46 * | cancel | cancel | cancel |
47 * V V | | +-----------+
48 * +-----------+ finish +------------+ | +-> | Failed |
49 * | Cancelled | <--------- | Cancelling | <---------------+ |(completed)|
50 * |(completed)| +------------+ +-----------+
Roman Elizarovd82b3a92017-06-23 21:52:08 +030051 * +-----------+
52 * ```
53 *
Roman Elizarov9fe5f462018-02-21 19:05:52 +030054 * A deferred value is a [Job]. A job in the
55 * [coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html)
56 * of [async] builder represents the coroutine itself.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030057 * A deferred value is active while the coroutine is working and cancellation aborts the coroutine when
58 * the coroutine is suspended on a _cancellable_ suspension point by throwing [CancellationException]
59 * or the cancellation cause inside the coroutine.
60 *
61 * 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 +030062 * cancelled or completes. Parent waits for all its [children] to complete in _completing_ or
Roman Elizarov8b38fa22017-09-27 17:44:31 +030063 * _cancelling_ state. _Completing_ state is purely internal. For an outside observer a _completing_
64 * deferred is still active, while internally it is waiting for its children.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030065 *
66 * All functions on this interface and on all interfaces derived from it are **thread-safe** and can
67 * be safely invoked from concurrent coroutines without external synchronization.
Roman Elizarov3754f952017-01-18 20:47:54 +030068 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +030069public interface Deferred<out T> : Job {
Roman Elizarov3754f952017-01-18 20:47:54 +030070 /**
Roman Elizarovb7c46de2017-02-08 12:35:24 +030071 * Returns `true` if computation of this deferred value has _completed exceptionally_ -- it had
72 * either _failed_ with exception during computation or was [cancelled][cancel].
Roman Elizarov32d95322017-02-09 15:57:31 +030073 *
74 * It implies that [isActive] is `false` and [isCompleted] is `true`.
Roman Elizarovb7c46de2017-02-08 12:35:24 +030075 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +030076 public val isCompletedExceptionally: Boolean
Roman Elizarovb7c46de2017-02-08 12:35:24 +030077
78 /**
Roman Elizarovbe4cae32017-02-15 17:57:02 +030079 * Awaits for completion of this value without blocking a thread and resumes when deferred computation is complete,
80 * returning the resulting value or throwing the corresponding exception if the deferred had completed exceptionally.
Roman Elizarov32d95322017-02-09 15:57:31 +030081 *
Roman Elizarovbe4cae32017-02-15 17:57:02 +030082 * This suspending function is cancellable.
Roman Elizarovd82b3a92017-06-23 21:52:08 +030083 * 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 +030084 * immediately resumes with [CancellationException].
Roman Elizarovd84dbc22017-02-22 14:56:58 +030085 *
Roman Elizarovdb0e22d2017-08-29 18:15:57 +030086 * This function can be used in [select] invocation with [onAwait] clause.
Roman Elizarovd84dbc22017-02-22 14:56:58 +030087 * Use [isCompleted] to check for completion of this deferred value without waiting.
Roman Elizarov3754f952017-01-18 20:47:54 +030088 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +030089 public suspend fun await(): T
Roman Elizarovc5814542017-01-19 10:19:06 +030090
91 /**
Roman Elizarovdb0e22d2017-08-29 18:15:57 +030092 * Clause for [select] expression of [await] suspending function that selects with the deferred value when it is
93 * resolved. The [select] invocation fails if the deferred value completes exceptionally (either fails or
94 * it cancelled).
Roman Elizarov1216e912017-02-22 09:57:06 +030095 */
Roman Elizarovdb0e22d2017-08-29 18:15:57 +030096 public val onAwait: SelectClause1<T>
Roman Elizarov1216e912017-02-22 09:57:06 +030097
98 /**
Roman Elizarov32d95322017-02-09 15:57:31 +030099 * Returns *completed* result or throws [IllegalStateException] if this deferred value has not
100 * [completed][isCompleted] yet. It throws the corresponding exception if this deferred has
101 * [completed exceptionally][isCompletedExceptionally].
102 *
Roman Elizarove7803472017-02-16 09:52:31 +0300103 * This function is designed to be used from [invokeOnCompletion] handlers, when there is an absolute certainty that
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300104 * the value is already complete. See also [getCompletionExceptionOrNull].
Roman Elizarovc5814542017-01-19 10:19:06 +0300105 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300106 public fun getCompleted(): T
Roman Elizarov32d95322017-02-09 15:57:31 +0300107
108 /**
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300109 * Returns *completion exception* result if this deferred [completed exceptionally][isCompletedExceptionally],
110 * `null` if it is completed normally, or throws [IllegalStateException] if this deferred value has not
111 * [completed][isCompleted] yet.
112 *
113 * This function is designed to be used from [invokeOnCompletion] handlers, when there is an absolute certainty that
114 * the value is already complete. See also [getCompleted].
115 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300116 public fun getCompletionExceptionOrNull(): Throwable?
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300117
118 /**
Roman Elizarovfc7a9a22017-02-13 11:54:01 +0300119 * @suppress **Deprecated**: Use `isActive`.
Roman Elizarov32d95322017-02-09 15:57:31 +0300120 */
121 @Deprecated(message = "Use `isActive`", replaceWith = ReplaceWith("isActive"))
122 public val isComputing: Boolean get() = isActive
Roman Elizarov3754f952017-01-18 20:47:54 +0300123}
124
125/**
Roman Elizarov32d95322017-02-09 15:57:31 +0300126 * Creates new coroutine and returns its future result as an implementation of [Deferred].
Roman Elizarov44ba4b12017-01-25 11:37:54 +0300127 *
Roman Elizarov32d95322017-02-09 15:57:31 +0300128 * The running coroutine is cancelled when the resulting object is [cancelled][Job.cancel].
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300129 *
130 * The [context] for the new coroutine can be explicitly specified.
131 * See [CoroutineDispatcher] for the standard context implementations that are provided by `kotlinx.coroutines`.
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300132 * The [coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html)
133 * of the parent coroutine may be used,
Roman Elizarov44ba4b12017-01-25 11:37:54 +0300134 * 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 +0300135 * The parent job may be also explicitly specified using [parent] parameter.
136 *
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300137 * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used.
Roman Elizarov32d95322017-02-09 15:57:31 +0300138 *
Roman Elizarov7b10c942017-05-16 21:02:51 +0300139 * By default, the coroutine is immediately scheduled for execution.
140 * Other options can be specified via `start` parameter. See [CoroutineStart] for details.
Roman Elizarovecda27f2017-04-06 23:06:26 +0300141 * An optional [start] parameter can be set to [CoroutineStart.LAZY] to start coroutine _lazily_. In this case,,
Roman Elizarov32d95322017-02-09 15:57:31 +0300142 * the resulting [Deferred] is created in _new_ state. It can be explicitly started with [start][Job.start]
Vsevolod Tolstopyatovf0ef14e2018-04-11 19:44:08 +0300143 * 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 +0300144 *
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300145 * @param context context of the coroutine. The default value is [DefaultDispatcher].
146 * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT].
Roman Elizarovfe8ba6b2018-03-13 17:34:29 +0300147 * @param parent explicitly specifies the parent job, overrides job from the [context] (if any).
148 * @param onCompletion optional completion handler for the coroutine (see [Job.invokeOnCompletion]).
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300149 * @param block the coroutine code.
Roman Elizarov3754f952017-01-18 20:47:54 +0300150 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300151public fun <T> async(
Roman Elizarovc0d559b2017-09-28 14:27:05 +0300152 context: CoroutineContext = DefaultDispatcher,
Roman Elizarovecda27f2017-04-06 23:06:26 +0300153 start: CoroutineStart = CoroutineStart.DEFAULT,
Roman Elizarove8f694e2017-11-28 10:12:00 +0300154 parent: Job? = null,
Roman Elizarovfe8ba6b2018-03-13 17:34:29 +0300155 onCompletion: CompletionHandler? = null,
Roman Elizarovecda27f2017-04-06 23:06:26 +0300156 block: suspend CoroutineScope.() -> T
157): Deferred<T> {
Roman Elizarove8f694e2017-11-28 10:12:00 +0300158 val newContext = newCoroutineContext(context, parent)
Roman Elizarovecda27f2017-04-06 23:06:26 +0300159 val coroutine = if (start.isLazy)
160 LazyDeferredCoroutine(newContext, block) else
161 DeferredCoroutine<T>(newContext, active = true)
Roman Elizarovfe8ba6b2018-03-13 17:34:29 +0300162 if (onCompletion != null) coroutine.invokeOnCompletion(handler = onCompletion)
Roman Elizarov2adf8bc2018-01-24 20:09:57 +0300163 coroutine.start(start, coroutine, block)
Roman Elizarov32d95322017-02-09 15:57:31 +0300164 return coroutine
165}
166
Roman Elizarove8f694e2017-11-28 10:12:00 +0300167/** @suppress **Deprecated**: Binary compatibility */
168@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
169public fun <T> async(
170 context: CoroutineContext = DefaultDispatcher,
171 start: CoroutineStart = CoroutineStart.DEFAULT,
Roman Elizarovfe8ba6b2018-03-13 17:34:29 +0300172 parent: Job? = null,
173 block: suspend CoroutineScope.() -> T
174): Deferred<T> = async(context, start, parent, block = block)
175
176/** @suppress **Deprecated**: Binary compatibility */
177@Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN)
178public fun <T> async(
179 context: CoroutineContext = DefaultDispatcher,
180 start: CoroutineStart = CoroutineStart.DEFAULT,
Roman Elizarove8f694e2017-11-28 10:12:00 +0300181 block: suspend CoroutineScope.() -> T
182): Deferred<T> =
183 async(context, start, block = block)
184
Roman Elizarov32d95322017-02-09 15:57:31 +0300185/**
Roman Elizarovecda27f2017-04-06 23:06:26 +0300186 * @suppress **Deprecated**: Use `start = CoroutineStart.XXX` parameter
187 */
188@Deprecated(message = "Use `start = CoroutineStart.XXX` parameter",
189 replaceWith = ReplaceWith("async(context, if (start) CoroutineStart.DEFAULT else CoroutineStart.LAZY, block)"))
190public fun <T> async(context: CoroutineContext, start: Boolean, block: suspend CoroutineScope.() -> T): Deferred<T> =
Roman Elizarove8f694e2017-11-28 10:12:00 +0300191 async(context, if (start) CoroutineStart.DEFAULT else CoroutineStart.LAZY, block = block)
Roman Elizarovecda27f2017-04-06 23:06:26 +0300192
193/**
Roman Elizarovfc7a9a22017-02-13 11:54:01 +0300194 * @suppress **Deprecated**: `defer` was renamed to `async`.
Roman Elizarov32d95322017-02-09 15:57:31 +0300195 */
196@Deprecated(message = "`defer` was renamed to `async`", level = DeprecationLevel.WARNING,
Roman Elizarovaa461cf2018-04-11 13:20:29 +0300197 replaceWith = ReplaceWith("async(context, block = block)"))
Roman Elizarovecda27f2017-04-06 23:06:26 +0300198public fun <T> defer(context: CoroutineContext, block: suspend CoroutineScope.() -> T): Deferred<T> =
Roman Elizarov32d95322017-02-09 15:57:31 +0300199 async(context, block = block)
Roman Elizarov3754f952017-01-18 20:47:54 +0300200
Roman Elizarov7a3afb52017-06-19 19:27:08 +0300201@Suppress("UNCHECKED_CAST")
Roman Elizarov32d95322017-02-09 15:57:31 +0300202private open class DeferredCoroutine<T>(
Roman Elizarov2b12d582017-06-22 20:12:19 +0300203 parentContext: CoroutineContext,
Roman Elizarov32d95322017-02-09 15:57:31 +0300204 active: Boolean
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300205) : AbstractCoroutine<T>(parentContext, active), Deferred<T>, SelectClause1<T> {
Roman Elizarov7a3afb52017-06-19 19:27:08 +0300206 override fun getCompleted(): T = getCompletedInternal() as T
Roman Elizarove3f28842017-12-21 19:15:40 +0300207 override suspend fun await(): T = awaitInternal() as T
Roman Elizarov6640b2b2018-01-17 19:08:55 +0300208 override val onAwait: SelectClause1<T> get() = this
209 override fun <R> registerSelectClause1(select: SelectInstance<R>, block: suspend (T) -> R) =
210 registerSelectClause1Internal(select, block)
Roman Elizarov1216e912017-02-22 09:57:06 +0300211}
212
Roman Elizarov32d95322017-02-09 15:57:31 +0300213private class LazyDeferredCoroutine<T>(
Roman Elizarov1216e912017-02-22 09:57:06 +0300214 parentContext: CoroutineContext,
215 private val block: suspend CoroutineScope.() -> T
216) : DeferredCoroutine<T>(parentContext, active = false) {
Roman Elizarov32d95322017-02-09 15:57:31 +0300217 override fun onStart() {
Roman Elizarova74eb5f2017-05-11 20:15:18 +0300218 block.startCoroutineCancellable(this, this)
Roman Elizarov32d95322017-02-09 15:57:31 +0300219 }
Roman Elizarov3754f952017-01-18 20:47:54 +0300220}