1 /*
2 * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4
5 package kotlinx.coroutines
6
7 import kotlinx.atomicfu.*
8 import kotlinx.coroutines.internal.*
9 import kotlin.coroutines.*
10 import kotlin.jvm.*
11
toStatenull12 internal fun <T> Result<T>.toState(
13 onCancellation: ((cause: Throwable) -> Unit)? = null
14 ): Any? = fold(
15 onSuccess = { if (onCancellation != null) CompletedWithCancellation(it, onCancellation) else it },
<lambda>null16 onFailure = { CompletedExceptionally(it) }
17 )
18
toStatenull19 internal fun <T> Result<T>.toState(caller: CancellableContinuation<*>): Any? = fold(
20 onSuccess = { it },
<lambda>null21 onFailure = { CompletedExceptionally(recoverStackTrace(it, caller)) }
22 )
23
24 @Suppress("RESULT_CLASS_IN_RETURN_TYPE", "UNCHECKED_CAST")
recoverResultnull25 internal fun <T> recoverResult(state: Any?, uCont: Continuation<T>): Result<T> =
26 if (state is CompletedExceptionally)
27 Result.failure(recoverStackTrace(state.cause, uCont))
28 else
29 Result.success(state as T)
30
31 internal data class CompletedWithCancellation(
32 @JvmField val result: Any?,
33 @JvmField val onCancellation: (cause: Throwable) -> Unit
34 )
35
36 /**
37 * Class for an internal state of a job that was cancelled (completed exceptionally).
38 *
39 * @param cause the exceptional completion cause. It's either original exceptional cause
40 * or artificial [CancellationException] if no cause was provided
41 */
42 internal open class CompletedExceptionally(
43 @JvmField val cause: Throwable,
44 handled: Boolean = false
45 ) {
46 private val _handled = atomic(handled)
47 val handled: Boolean get() = _handled.value
48 fun makeHandled(): Boolean = _handled.compareAndSet(false, true)
49 override fun toString(): String = "$classSimpleName[$cause]"
50 }
51
52 /**
53 * A specific subclass of [CompletedExceptionally] for cancelled [AbstractContinuation].
54 *
55 * @param continuation the continuation that was cancelled.
56 * @param cause the exceptional completion cause. If `cause` is null, then a [CancellationException]
57 * if created on first access to [exception] property.
58 */
59 internal class CancelledContinuation(
60 continuation: Continuation<*>,
61 cause: Throwable?,
62 handled: Boolean
63 ) : CompletedExceptionally(cause ?: CancellationException("Continuation $continuation was cancelled normally"), handled) {
64 private val _resumed = atomic(false)
makeResumednull65 fun makeResumed(): Boolean = _resumed.compareAndSet(false, true)
66 }
67