Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 1 | /* |
Vsevolod Tolstopyatov | 6d1a6e3 | 2020-02-18 15:28:00 +0300 | [diff] [blame^] | 2 | * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 3 | */ |
| 4 | |
Roman Elizarov | 0950dfa | 2018-07-13 10:33:25 +0300 | [diff] [blame] | 5 | package kotlinx.coroutines |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 6 | |
Roman Elizarov | 0950dfa | 2018-07-13 10:33:25 +0300 | [diff] [blame] | 7 | import kotlinx.coroutines.CoroutineStart.* |
| 8 | import kotlinx.coroutines.intrinsics.* |
| 9 | import kotlin.coroutines.* |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 10 | |
| 11 | /** |
paolop | c51bde0 | 2018-06-09 09:40:11 +0000 | [diff] [blame] | 12 | * Defines start options for coroutines builders. |
Roman Elizarov | c32579e | 2018-09-09 19:21:43 +0300 | [diff] [blame] | 13 | * It is used in `start` parameter of [launch][CoroutineScope.launch], [async][CoroutineScope.async], and other coroutine builder functions. |
Roman Elizarov | 7b10c94 | 2017-05-16 21:02:51 +0300 | [diff] [blame] | 14 | * |
| 15 | * The summary of coroutine start options is: |
| 16 | * * [DEFAULT] -- immediately schedules coroutine for execution according to its context; |
| 17 | * * [LAZY] -- starts coroutine lazily, only when it is needed; |
Roman Elizarov | 23fb728 | 2018-01-24 23:09:42 +0300 | [diff] [blame] | 18 | * * [ATOMIC] -- atomically (in a non-cancellable way) schedules coroutine for execution according to its context; |
Roman Elizarov | 7b10c94 | 2017-05-16 21:02:51 +0300 | [diff] [blame] | 19 | * * [UNDISPATCHED] -- immediately executes coroutine until its first suspension point _in the current thread_. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 20 | */ |
Roman Elizarov | 23fb728 | 2018-01-24 23:09:42 +0300 | [diff] [blame] | 21 | public enum class CoroutineStart { |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 22 | /** |
Inego | 39f92ca | 2019-04-21 13:30:55 +0700 | [diff] [blame] | 23 | * Default -- immediately schedules the coroutine for execution according to its context. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 24 | * |
| 25 | * If the [CoroutineDispatcher] of the coroutine context returns `true` from [CoroutineDispatcher.isDispatchNeeded] |
| 26 | * function as most dispatchers do, then the coroutine code is dispatched for execution later, while the code that |
| 27 | * invoked the coroutine builder continues execution. |
| 28 | * |
Inego | ebe519a | 2019-04-21 13:22:27 +0700 | [diff] [blame] | 29 | * Note that [Dispatchers.Unconfined] always returns `false` from its [CoroutineDispatcher.isDispatchNeeded] |
Inego | 39f92ca | 2019-04-21 13:30:55 +0700 | [diff] [blame] | 30 | * function, so starting a coroutine with [Dispatchers.Unconfined] by [DEFAULT] is the same as using [UNDISPATCHED]. |
Roman Elizarov | a74eb5f | 2017-05-11 20:15:18 +0300 | [diff] [blame] | 31 | * |
| 32 | * If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its |
paolop | c51bde0 | 2018-06-09 09:40:11 +0000 | [diff] [blame] | 33 | * execution at all, but will complete with an exception. |
Roman Elizarov | a74eb5f | 2017-05-11 20:15:18 +0300 | [diff] [blame] | 34 | * |
Inego | 39f92ca | 2019-04-21 13:30:55 +0700 | [diff] [blame] | 35 | * Cancellability of a coroutine at suspension points depends on the particular implementation details of |
Roman Elizarov | a74eb5f | 2017-05-11 20:15:18 +0300 | [diff] [blame] | 36 | * suspending functions. Use [suspendCancellableCoroutine] to implement cancellable suspending functions. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 37 | */ |
| 38 | DEFAULT, |
| 39 | |
| 40 | /** |
Inego | 39f92ca | 2019-04-21 13:30:55 +0700 | [diff] [blame] | 41 | * Starts the coroutine lazily, only when it is needed. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 42 | * |
Roman Elizarov | 23fb728 | 2018-01-24 23:09:42 +0300 | [diff] [blame] | 43 | * See the documentation for the corresponding coroutine builders for details |
Roman Elizarov | c32579e | 2018-09-09 19:21:43 +0300 | [diff] [blame] | 44 | * (like [launch][CoroutineScope.launch] and [async][CoroutineScope.async]). |
Roman Elizarov | a74eb5f | 2017-05-11 20:15:18 +0300 | [diff] [blame] | 45 | * |
| 46 | * If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its |
paolop | c51bde0 | 2018-06-09 09:40:11 +0000 | [diff] [blame] | 47 | * execution at all, but will complete with an exception. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 48 | */ |
| 49 | LAZY, |
| 50 | |
| 51 | /** |
Inego | 39f92ca | 2019-04-21 13:30:55 +0700 | [diff] [blame] | 52 | * Atomically (i.e., in a non-cancellable way) schedules the coroutine for execution according to its context. |
Roman Elizarov | 7b10c94 | 2017-05-16 21:02:51 +0300 | [diff] [blame] | 53 | * This is similar to [DEFAULT], but the coroutine cannot be cancelled before it starts executing. |
Roman Elizarov | a74eb5f | 2017-05-11 20:15:18 +0300 | [diff] [blame] | 54 | * |
| 55 | * Cancellability of coroutine at suspension points depends on the particular implementation details of |
| 56 | * suspending functions as in [DEFAULT]. |
| 57 | */ |
Vsevolod Tolstopyatov | b5d10d4 | 2018-09-28 16:28:16 +0300 | [diff] [blame] | 58 | @ExperimentalCoroutinesApi |
Roman Elizarov | a74eb5f | 2017-05-11 20:15:18 +0300 | [diff] [blame] | 59 | ATOMIC, |
| 60 | |
| 61 | /** |
Inego | 39f92ca | 2019-04-21 13:30:55 +0700 | [diff] [blame] | 62 | * Immediately executes the coroutine until its first suspension point _in the current thread_ as if the |
Yanis Batura | 8140cfe | 2019-04-27 21:31:14 +0700 | [diff] [blame] | 63 | * coroutine was started using [Dispatchers.Unconfined]. However, when the coroutine is resumed from suspension |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 64 | * it is dispatched according to the [CoroutineDispatcher] in its context. |
Roman Elizarov | 4eae2a8 | 2017-05-17 20:55:27 +0300 | [diff] [blame] | 65 | * |
| 66 | * This is similar to [ATOMIC] in the sense that coroutine starts executing even if it was already cancelled, |
paolop | c51bde0 | 2018-06-09 09:40:11 +0000 | [diff] [blame] | 67 | * but the difference is that it starts executing in the same thread. |
Roman Elizarov | 4eae2a8 | 2017-05-17 20:55:27 +0300 | [diff] [blame] | 68 | * |
| 69 | * Cancellability of coroutine at suspension points depends on the particular implementation details of |
| 70 | * suspending functions as in [DEFAULT]. |
Roman Elizarov | 27b8f45 | 2018-09-20 21:23:41 +0300 | [diff] [blame] | 71 | * |
| 72 | * **Note: This is an experimental api.** Execution semantics of coroutines may change in the future when this mode is used. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 73 | */ |
Roman Elizarov | 27b8f45 | 2018-09-20 21:23:41 +0300 | [diff] [blame] | 74 | @ExperimentalCoroutinesApi |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 75 | UNDISPATCHED; |
| 76 | |
| 77 | /** |
Inego | 39f92ca | 2019-04-21 13:30:55 +0700 | [diff] [blame] | 78 | * Starts the corresponding block as a coroutine with this coroutine's start strategy. |
Roman Elizarov | 4eae2a8 | 2017-05-17 20:55:27 +0300 | [diff] [blame] | 79 | * |
| 80 | * * [DEFAULT] uses [startCoroutineCancellable]. |
| 81 | * * [ATOMIC] uses [startCoroutine]. |
| 82 | * * [UNDISPATCHED] uses [startCoroutineUndispatched]. |
| 83 | * * [LAZY] does nothing. |
Roman Elizarov | 27b8f45 | 2018-09-20 21:23:41 +0300 | [diff] [blame] | 84 | * |
| 85 | * @suppress **This an internal API and should not be used from general code.** |
Roman Elizarov | 4eae2a8 | 2017-05-17 20:55:27 +0300 | [diff] [blame] | 86 | */ |
Roman Elizarov | 27b8f45 | 2018-09-20 21:23:41 +0300 | [diff] [blame] | 87 | @InternalCoroutinesApi |
Roman Elizarov | 23fb728 | 2018-01-24 23:09:42 +0300 | [diff] [blame] | 88 | public operator fun <T> invoke(block: suspend () -> T, completion: Continuation<T>) = |
Roman Elizarov | 4eae2a8 | 2017-05-17 20:55:27 +0300 | [diff] [blame] | 89 | when (this) { |
| 90 | CoroutineStart.DEFAULT -> block.startCoroutineCancellable(completion) |
| 91 | CoroutineStart.ATOMIC -> block.startCoroutine(completion) |
| 92 | CoroutineStart.UNDISPATCHED -> block.startCoroutineUndispatched(completion) |
| 93 | CoroutineStart.LAZY -> Unit // will start lazily |
| 94 | } |
| 95 | |
| 96 | /** |
Roman Elizarov | 7b10c94 | 2017-05-16 21:02:51 +0300 | [diff] [blame] | 97 | * Starts the corresponding block with receiver as a coroutine with this coroutine start strategy. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 98 | * |
Roman Elizarov | a74eb5f | 2017-05-11 20:15:18 +0300 | [diff] [blame] | 99 | * * [DEFAULT] uses [startCoroutineCancellable]. |
| 100 | * * [ATOMIC] uses [startCoroutine]. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 101 | * * [UNDISPATCHED] uses [startCoroutineUndispatched]. |
| 102 | * * [LAZY] does nothing. |
Roman Elizarov | 27b8f45 | 2018-09-20 21:23:41 +0300 | [diff] [blame] | 103 | * |
| 104 | * @suppress **This an internal API and should not be used from general code.** |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 105 | */ |
Roman Elizarov | 27b8f45 | 2018-09-20 21:23:41 +0300 | [diff] [blame] | 106 | @InternalCoroutinesApi |
Roman Elizarov | 23fb728 | 2018-01-24 23:09:42 +0300 | [diff] [blame] | 107 | public operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>) = |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 108 | when (this) { |
Roman Elizarov | a74eb5f | 2017-05-11 20:15:18 +0300 | [diff] [blame] | 109 | CoroutineStart.DEFAULT -> block.startCoroutineCancellable(receiver, completion) |
| 110 | CoroutineStart.ATOMIC -> block.startCoroutine(receiver, completion) |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 111 | CoroutineStart.UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion) |
| 112 | CoroutineStart.LAZY -> Unit // will start lazily |
| 113 | } |
| 114 | |
| 115 | /** |
| 116 | * Returns `true` when [LAZY]. |
Roman Elizarov | 27b8f45 | 2018-09-20 21:23:41 +0300 | [diff] [blame] | 117 | * |
| 118 | * @suppress **This an internal API and should not be used from general code.** |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 119 | */ |
Roman Elizarov | 27b8f45 | 2018-09-20 21:23:41 +0300 | [diff] [blame] | 120 | @InternalCoroutinesApi |
Roman Elizarov | 23fb728 | 2018-01-24 23:09:42 +0300 | [diff] [blame] | 121 | public val isLazy: Boolean get() = this === LAZY |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 122 | } |