blob: ce285bfd8c7880569d3eca047758484cc6bfc121 [file] [log] [blame]
Roman Elizarove3f28842017-12-21 19:15:40 +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
19import kotlin.coroutines.experimental.ContinuationInterceptor
20import kotlin.coroutines.experimental.CoroutineContext
21
22/**
23 * Deferred value is a non-blocking cancellable future.
24 *
25 * It is created with [async] coroutine builder or via constructor of [CompletableDeferred] class.
26 * It is in [active][isActive] state while the value is being computed.
27 *
28 * Deferred value has the following states:
29 *
30 * | **State** | [isActive] | [isCompleted] | [isCompletedExceptionally] | [isCancelled] |
31 * | --------------------------------------- | ---------- | ------------- | -------------------------- | ------------- |
32 * | _New_ (optional initial state) | `false` | `false` | `false` | `false` |
33 * | _Active_ (default initial state) | `true` | `false` | `false` | `false` |
34 * | _Completing_ (optional transient state) | `true` | `false` | `false` | `false` |
35 * | _Cancelling_ (optional transient state) | `false` | `false` | `false` | `true` |
36 * | _Cancelled_ (final state) | `false` | `true` | `true` | `true` |
37 * | _Resolved_ (final state) | `false` | `true` | `false` | `false` |
38 * | _Failed_ (final state) | `false` | `true` | `true` | `false` |
39 *
40 * Usually, a deferred value is created in _active_ state (it is created and started).
41 * However, [async] coroutine builder has an optional `start` parameter that creates a deferred value in _new_ state
42 * when this parameter is set to [CoroutineStart.LAZY].
43 * Such a deferred can be be made _active_ by invoking [start], [join], or [await].
44 *
45 * A deferred can be _cancelled_ at any time with [cancel] function that forces it to transition to
Roman Elizarov4d626de2018-01-11 22:57:28 +030046 * _cancelling_ state immediately. Deferred that is not backed by a coroutine (see [CompletableDeferred]) and does not have
47 * [children] becomes _cancelled_ on [cancel] immediately.
48 * Otherwise, deferred becomes _cancelled_ when it finishes executing its code and
49 * when all its children [complete][isCompleted].
Roman Elizarove3f28842017-12-21 19:15:40 +030050 *
51 * ```
52 * wait children
53 * +-----+ start +--------+ complete +-------------+ finish +-----------+
54 * | New | ---------------> | Active | ----------> | Completing | ---+-> | Resolved |
55 * +-----+ +--------+ +-------------+ | |(completed)|
56 * | | | | +-----------+
57 * | cancel | cancel | cancel |
58 * V V | | +-----------+
59 * +-----------+ finish +------------+ | +-> | Failed |
60 * | Cancelled | <--------- | Cancelling | <---------------+ |(completed)|
61 * |(completed)| +------------+ +-----------+
62 * +-----------+
63 * ```
64 *
65 * A deferred value is a [Job]. A job in the coroutine [context][CoroutineScope.coroutineContext] of [async] builder
66 * represents the coroutine itself.
67 * A deferred value is active while the coroutine is working and cancellation aborts the coroutine when
68 * the coroutine is suspended on a _cancellable_ suspension point by throwing [CancellationException]
69 * or the cancellation cause inside the coroutine.
70 *
71 * A deferred value can have a _parent_ job. A deferred value with a parent is cancelled when its parent is
72 * cancelled or completes. Parent waits for all its [children] to complete in _completing_ or
73 * _cancelling_ state. _Completing_ state is purely internal. For an outside observer a _completing_
74 * deferred is still active, while internally it is waiting for its children.
75 *
76 * All functions on this interface and on all interfaces derived from it are **thread-safe** and can
77 * be safely invoked from concurrent coroutines without external synchronization.
78 */
79public actual interface Deferred<out T> : Job {
80 /**
81 * Returns `true` if computation of this deferred value has _completed exceptionally_ -- it had
82 * either _failed_ with exception during computation or was [cancelled][cancel].
83 *
84 * It implies that [isActive] is `false` and [isCompleted] is `true`.
85 */
86 public actual val isCompletedExceptionally: Boolean
87
88 /**
89 * Awaits for completion of this value without blocking a thread and resumes when deferred computation is complete,
90 * returning the resulting value or throwing the corresponding exception if the deferred had completed exceptionally.
91 *
92 * This suspending function is cancellable.
93 * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
94 * immediately resumes with [CancellationException].
95 */
96 public actual suspend fun await(): T
97
98 /**
99 * 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 *
103 * This function is designed to be used from [invokeOnCompletion] handlers, when there is an absolute certainty that
104 * the value is already complete. See also [getCompletionExceptionOrNull].
105 */
106 public actual fun getCompleted(): T
107
108 /**
109 * 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 */
116 public actual fun getCompletionExceptionOrNull(): Throwable?
117}
118
119/**
120 * Creates new coroutine and returns its future result as an implementation of [Deferred].
121 *
122 * The running coroutine is cancelled when the resulting object is [cancelled][Job.cancel].
123 *
124 * The [context] for the new coroutine can be explicitly specified.
125 * See [CoroutineDispatcher] for the standard context implementations that are provided by `kotlinx.coroutines`.
126 * The [context][CoroutineScope.coroutineContext] of the parent coroutine from its [scope][CoroutineScope] may be used,
127 * in which case the [Job] of the resulting coroutine is a child of the job of the parent coroutine.
128 * The parent job may be also explicitly specified using [parent] parameter.
129 *
130 * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used.
131 *
132 * By default, the coroutine is immediately scheduled for execution.
133 * Other options can be specified via `start` parameter. See [CoroutineStart] for details.
134 * An optional [start] parameter can be set to [CoroutineStart.LAZY] to start coroutine _lazily_. In this case,,
135 * the resulting [Deferred] is created in _new_ state. It can be explicitly started with [start][Job.start]
136 * function and will be started implicitly on the first invocation of [join][Job.join] or [await][Deferred.await].
137 *
138 * @param context context of the coroutine. The default value is [DefaultDispatcher].
139 * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT].
140 * @param parent explicitly specifies the parent job, overrides job from the [context] (if any).*
141 * @param block the coroutine code.
142 */
143public actual fun <T> async(
144 context: CoroutineContext = DefaultDispatcher,
145 start: CoroutineStart = CoroutineStart.DEFAULT,
146 parent: Job? = null,
147 block: suspend CoroutineScope.() -> T
148): Deferred<T> {
149 val newContext = newCoroutineContext(context, parent)
150 val coroutine = if (start.isLazy)
151 LazyDeferredCoroutine(newContext, block) else
152 DeferredCoroutine<T>(newContext, active = true)
153 coroutine.initParentJob(newContext[Job])
154 start(block, coroutine, coroutine)
155 return coroutine
156}
157
158@Suppress("UNCHECKED_CAST")
159private open class DeferredCoroutine<T>(
160 parentContext: CoroutineContext,
161 active: Boolean
162) : AbstractCoroutine<T>(parentContext, active), Deferred<T> {
163 override fun getCompleted(): T = getCompletedInternal() as T
164 override suspend fun await(): T = awaitInternal() as T
165}
166
167private class LazyDeferredCoroutine<T>(
168 parentContext: CoroutineContext,
169 private val block: suspend CoroutineScope.() -> T
170) : DeferredCoroutine<T>(parentContext, active = false) {
171 override fun onStart() {
172 block.startCoroutineCancellable(this, this)
173 }
174}