Roman Elizarov | a7db8ec | 2017-12-21 22:45:12 +0300 | [diff] [blame] | 1 | /* |
| 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 Elizarov | e1c0b65 | 2017-12-01 14:02:57 +0300 | [diff] [blame] | 17 | package kotlinx.coroutines.experimental |
| 18 | |
| 19 | import kotlinx.coroutines.experimental.intrinsics.startCoroutineUndispatched |
| 20 | import kotlin.coroutines.experimental.Continuation |
| 21 | import kotlin.coroutines.experimental.startCoroutine |
| 22 | |
| 23 | /** |
| 24 | * Defines start option for coroutines builders. |
| 25 | * It is used in `start` parameter of [launch], [async], and [actor][kotlinx.coroutines.experimental.channels.actor] |
| 26 | * coroutine builder functions. |
| 27 | * |
| 28 | * The summary of coroutine start options is: |
| 29 | * * [DEFAULT] -- immediately schedules coroutine for execution according to its context; |
| 30 | * * [LAZY] -- starts coroutine lazily, only when it is needed; |
| 31 | * * [ATOMIC] -- atomically (non-cancellably) schedules coroutine for execution according to its context; |
| 32 | * * [UNDISPATCHED] -- immediately executes coroutine until its first suspension point _in the current thread_. |
| 33 | */ |
| 34 | public actual enum class CoroutineStart { |
| 35 | /** |
| 36 | * Default -- immediately schedules coroutine for execution according to its context. |
| 37 | * |
| 38 | * If the [CoroutineDispatcher] of the coroutine context returns `true` from [CoroutineDispatcher.isDispatchNeeded] |
| 39 | * function as most dispatchers do, then the coroutine code is dispatched for execution later, while the code that |
| 40 | * invoked the coroutine builder continues execution. |
| 41 | * |
| 42 | * Note, that [Unconfined] dispatcher always returns `false` from its [CoroutineDispatcher.isDispatchNeeded] |
| 43 | * function, so starting coroutine with [Unconfined] dispatcher by [DEFAULT] is the same as using [UNDISPATCHED]. |
| 44 | * |
| 45 | * If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its |
| 46 | * execution at all, but complete with an exception. |
| 47 | * |
| 48 | * Cancellability of coroutine at suspension points depends on the particular implementation details of |
| 49 | * suspending functions. Use [suspendCancellableCoroutine] to implement cancellable suspending functions. |
| 50 | */ |
| 51 | DEFAULT, |
| 52 | |
| 53 | /** |
| 54 | * Starts coroutine lazily, only when it is needed. |
| 55 | * |
| 56 | * See the documentation for the corresponding coroutine builders for details: |
| 57 | * [launch], [async], and [actor][kotlinx.coroutines.experimental.channels.actor]. |
| 58 | * |
| 59 | * If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its |
| 60 | * execution at all, but complete with an exception. |
| 61 | */ |
| 62 | LAZY, |
| 63 | |
| 64 | /** |
| 65 | * Atomically (non-cancellably) schedules coroutine for execution according to its context. |
| 66 | * This is similar to [DEFAULT], but the coroutine cannot be cancelled before it starts executing. |
| 67 | * |
| 68 | * Cancellability of coroutine at suspension points depends on the particular implementation details of |
| 69 | * suspending functions as in [DEFAULT]. |
| 70 | */ |
| 71 | ATOMIC, |
| 72 | |
| 73 | /** |
| 74 | * Immediately executes coroutine until its first suspension point _in the current thread_ as if it the |
| 75 | * coroutine was started using [Unconfined] dispatcher. However, when coroutine is resumed from suspension |
| 76 | * it is dispatched according to the [CoroutineDispatcher] in its context. |
| 77 | * |
| 78 | * This is similar to [ATOMIC] in the sense that coroutine starts executing even if it was already cancelled, |
| 79 | * but the difference is that it start executing in the same thread. |
| 80 | * |
| 81 | * Cancellability of coroutine at suspension points depends on the particular implementation details of |
| 82 | * suspending functions as in [DEFAULT]. |
| 83 | */ |
| 84 | UNDISPATCHED; |
| 85 | |
| 86 | /** |
| 87 | * Starts the corresponding block as a coroutine with this coroutine start strategy. |
| 88 | * |
| 89 | * * [DEFAULT] uses [startCoroutineCancellable]. |
| 90 | * * [ATOMIC] uses [startCoroutine]. |
| 91 | * * [UNDISPATCHED] uses [startCoroutineUndispatched]. |
| 92 | * * [LAZY] does nothing. |
| 93 | */ |
| 94 | public actual operator fun <T> invoke(block: suspend () -> T, completion: Continuation<T>) = |
| 95 | when (this) { |
| 96 | CoroutineStart.DEFAULT -> block.startCoroutineCancellable(completion) |
| 97 | CoroutineStart.ATOMIC -> block.startCoroutine(completion) |
| 98 | CoroutineStart.UNDISPATCHED -> block.startCoroutineUndispatched(completion) |
| 99 | CoroutineStart.LAZY -> Unit // will start lazily |
| 100 | } |
| 101 | |
| 102 | /** |
| 103 | * Starts the corresponding block with receiver as a coroutine with this coroutine start strategy. |
| 104 | * |
| 105 | * * [DEFAULT] uses [startCoroutineCancellable]. |
| 106 | * * [ATOMIC] uses [startCoroutine]. |
| 107 | * * [UNDISPATCHED] uses [startCoroutineUndispatched]. |
| 108 | * * [LAZY] does nothing. |
| 109 | */ |
| 110 | public actual operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>) = |
| 111 | when (this) { |
| 112 | CoroutineStart.DEFAULT -> block.startCoroutineCancellable(receiver, completion) |
| 113 | CoroutineStart.ATOMIC -> block.startCoroutine(receiver, completion) |
| 114 | CoroutineStart.UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion) |
| 115 | CoroutineStart.LAZY -> Unit // will start lazily |
| 116 | } |
| 117 | |
| 118 | /** |
| 119 | * Returns `true` when [LAZY]. |
| 120 | */ |
| 121 | public actual val isLazy: Boolean get() = this === LAZY |
| 122 | } |