blob: 05e80e3ed72365f2c06ac202bf2b5929a9b90864 [file] [log] [blame]
/*
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("NO_EXPLICIT_VISIBILITY_IN_API_MODE")
package kotlinx.coroutines
import kotlinx.coroutines.CoroutineStart.*
import kotlinx.coroutines.intrinsics.*
import kotlin.coroutines.*
/**
* Defines start options for coroutines builders.
* It is used in `start` parameter of [launch][CoroutineScope.launch], [async][CoroutineScope.async], and other coroutine builder functions.
*
* The summary of coroutine start options is:
* * [DEFAULT] -- immediately schedules coroutine for execution according to its context;
* * [LAZY] -- starts coroutine lazily, only when it is needed;
* * [ATOMIC] -- atomically (in a non-cancellable way) schedules coroutine for execution according to its context;
* * [UNDISPATCHED] -- immediately executes coroutine until its first suspension point _in the current thread_.
*/
public enum class CoroutineStart {
/**
* Default -- immediately schedules the coroutine for execution according to its context.
*
* If the [CoroutineDispatcher] of the coroutine context returns `true` from [CoroutineDispatcher.isDispatchNeeded]
* function as most dispatchers do, then the coroutine code is dispatched for execution later, while the code that
* invoked the coroutine builder continues execution.
*
* Note that [Dispatchers.Unconfined] always returns `false` from its [CoroutineDispatcher.isDispatchNeeded]
* function, so starting a coroutine with [Dispatchers.Unconfined] by [DEFAULT] is the same as using [UNDISPATCHED].
*
* If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its
* execution at all, but will complete with an exception.
*
* Cancellability of a coroutine at suspension points depends on the particular implementation details of
* suspending functions. Use [suspendCancellableCoroutine] to implement cancellable suspending functions.
*/
DEFAULT,
/**
* Starts the coroutine lazily, only when it is needed.
*
* See the documentation for the corresponding coroutine builders for details
* (like [launch][CoroutineScope.launch] and [async][CoroutineScope.async]).
*
* If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its
* execution at all, but will complete with an exception.
*/
LAZY,
/**
* Atomically (i.e., in a non-cancellable way) schedules the coroutine for execution according to its context.
* This is similar to [DEFAULT], but the coroutine cannot be cancelled before it starts executing.
*
* Cancellability of coroutine at suspension points depends on the particular implementation details of
* suspending functions as in [DEFAULT].
*/
@ExperimentalCoroutinesApi
ATOMIC,
/**
* Immediately executes the coroutine until its first suspension point _in the current thread_ as if the
* coroutine was started using [Dispatchers.Unconfined]. However, when the coroutine is resumed from suspension
* it is dispatched according to the [CoroutineDispatcher] in its context.
*
* This is similar to [ATOMIC] in the sense that coroutine starts executing even if it was already cancelled,
* but the difference is that it starts executing in the same thread.
*
* Cancellability of coroutine at suspension points depends on the particular implementation details of
* suspending functions as in [DEFAULT].
*
* **Note: This is an experimental api.** Execution semantics of coroutines may change in the future when this mode is used.
*/
@ExperimentalCoroutinesApi
UNDISPATCHED;
/**
* Starts the corresponding block as a coroutine with this coroutine's start strategy.
*
* * [DEFAULT] uses [startCoroutineCancellable].
* * [ATOMIC] uses [startCoroutine].
* * [UNDISPATCHED] uses [startCoroutineUndispatched].
* * [LAZY] does nothing.
*
* @suppress **This an internal API and should not be used from general code.**
*/
@InternalCoroutinesApi
public operator fun <T> invoke(block: suspend () -> T, completion: Continuation<T>): Unit =
when (this) {
DEFAULT -> block.startCoroutineCancellable(completion)
ATOMIC -> block.startCoroutine(completion)
UNDISPATCHED -> block.startCoroutineUndispatched(completion)
LAZY -> Unit // will start lazily
}
/**
* Starts the corresponding block with receiver as a coroutine with this coroutine start strategy.
*
* * [DEFAULT] uses [startCoroutineCancellable].
* * [ATOMIC] uses [startCoroutine].
* * [UNDISPATCHED] uses [startCoroutineUndispatched].
* * [LAZY] does nothing.
*
* @suppress **This an internal API and should not be used from general code.**
*/
@InternalCoroutinesApi
public operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>): Unit =
when (this) {
DEFAULT -> block.startCoroutineCancellable(receiver, completion)
ATOMIC -> block.startCoroutine(receiver, completion)
UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion)
LAZY -> Unit // will start lazily
}
/**
* Returns `true` when [LAZY].
*
* @suppress **This an internal API and should not be used from general code.**
*/
@InternalCoroutinesApi
public val isLazy: Boolean get() = this === LAZY
}