• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 package kotlinx.coroutines
5 
6 import kotlinx.coroutines.CoroutineStart.*
7 import kotlinx.coroutines.intrinsics.*
8 import kotlin.coroutines.*
9 
10 /**
11  * Defines start options for coroutines builders.
12  * It is used in `start` parameter of [launch][CoroutineScope.launch], [async][CoroutineScope.async], and other coroutine builder functions.
13  *
14  * The summary of coroutine start options is:
15  * * [DEFAULT] -- immediately schedules coroutine for execution according to its context;
16  * * [LAZY] -- starts coroutine lazily, only when it is needed;
17  * * [ATOMIC] -- atomically (in a non-cancellable way) schedules coroutine for execution according to its context;
18  * * [UNDISPATCHED] -- immediately executes coroutine until its first suspension point _in the current thread_.
19  */
20 public enum class CoroutineStart {
21     /**
22      * Default -- immediately schedules the coroutine for execution according to its context.
23      *
24      * If the [CoroutineDispatcher] of the coroutine context returns `true` from [CoroutineDispatcher.isDispatchNeeded]
25      * function as most dispatchers do, then the coroutine code is dispatched for execution later, while the code that
26      * invoked the coroutine builder continues execution.
27      *
28      * Note that [Dispatchers.Unconfined] always returns `false` from its [CoroutineDispatcher.isDispatchNeeded]
29      * function, so starting a coroutine with [Dispatchers.Unconfined] by [DEFAULT] is the same as using [UNDISPATCHED].
30      *
31      * If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its
32      * execution at all, but will complete with an exception.
33      *
34      * Cancellability of a coroutine at suspension points depends on the particular implementation details of
35      * suspending functions. Use [suspendCancellableCoroutine] to implement cancellable suspending functions.
36      */
37     DEFAULT,
38 
39     /**
40      * Starts the coroutine lazily, only when it is needed.
41      *
42      * See the documentation for the corresponding coroutine builders for details
43      * (like [launch][CoroutineScope.launch] and [async][CoroutineScope.async]).
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 will complete with an exception.
47      */
48     LAZY,
49 
50     /**
51      * Atomically (i.e., in a non-cancellable way) schedules the coroutine for execution according to its context.
52      * This is similar to [DEFAULT], but the coroutine cannot be cancelled before it starts executing.
53      *
54      * Cancellability of coroutine at suspension points depends on the particular implementation details of
55      * suspending functions as in [DEFAULT].
56      */
57     @ExperimentalCoroutinesApi // Since 1.0.0, no ETA on stability
58     ATOMIC,
59 
60     /**
61      * Immediately executes the coroutine until its first suspension point _in the current thread_ similarly to
62      * the coroutine being started using [Dispatchers.Unconfined]. However, when the coroutine is resumed from suspension
63      * it is dispatched according to the [CoroutineDispatcher] in its context.
64      *
65      * This is similar to [ATOMIC] in the sense that coroutine starts executing even if it was already cancelled,
66      * but the difference is that it starts executing in the same thread.
67      *
68      * Cancellability of coroutine at suspension points depends on the particular implementation details of
69      * suspending functions as in [DEFAULT].
70      *
71      * ### Unconfined event loop
72      *
73      * Unlike [Dispatchers.Unconfined] and [MainCoroutineDispatcher.immediate], nested undispatched coroutines do not form
74      * an event loop that otherwise prevents potential stack overflow in case of unlimited nesting.
75      */
76     UNDISPATCHED;
77 
78     /**
79      * Starts the corresponding block as a coroutine with this coroutine's start strategy.
80      *
81      * * [DEFAULT] uses [startCoroutineCancellable].
82      * * [ATOMIC] uses [startCoroutine].
83      * * [UNDISPATCHED] uses [startCoroutineUndispatched].
84      * * [LAZY] does nothing.
85      *
86      * @suppress **This an internal API and should not be used from general code.**
87      */
88     @InternalCoroutinesApi
invokenull89     public operator fun <T> invoke(block: suspend () -> T, completion: Continuation<T>): Unit =
90         when (this) {
91             DEFAULT -> block.startCoroutineCancellable(completion)
92             ATOMIC -> block.startCoroutine(completion)
93             UNDISPATCHED -> block.startCoroutineUndispatched(completion)
94             LAZY -> Unit // will start lazily
95         }
96 
97     /**
98      * Starts the corresponding block with receiver as a coroutine with this coroutine start strategy.
99      *
100      * * [DEFAULT] uses [startCoroutineCancellable].
101      * * [ATOMIC] uses [startCoroutine].
102      * * [UNDISPATCHED] uses [startCoroutineUndispatched].
103      * * [LAZY] does nothing.
104      *
105      * @suppress **This an internal API and should not be used from general code.**
106      */
107     @InternalCoroutinesApi
invokenull108     public operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>): Unit =
109         when (this) {
110             DEFAULT -> block.startCoroutineCancellable(receiver, completion)
111             ATOMIC -> block.startCoroutine(receiver, completion)
112             UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion)
113             LAZY -> Unit // will start lazily
114         }
115 
116     /**
117      * Returns `true` when [LAZY].
118      *
119      * @suppress **This an internal API and should not be used from general code.**
120      */
121     @InternalCoroutinesApi
122     public val isLazy: Boolean get() = this === LAZY
123 }
124