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