1 package kotlinx.coroutines
2 
3 /**
4  * Handler for [Job.invokeOnCompletion] and [CancellableContinuation.invokeOnCancellation].
5  *
6  * The meaning of `cause` that is passed to the handler is:
7  * - It is `null` if the job has completed normally or the continuation was cancelled without a `cause`.
8  * - It is an instance of [CancellationException] if the job or the continuation was cancelled _normally_.
9  *   **It should not be treated as an error**. In particular, it should not be reported to error logs.
10  * - Otherwise, the job or the continuation had _failed_.
11  *
12  * A function used for this should not throw any exceptions.
13  * If it does, they will get caught, wrapped into [CompletionHandlerException], and then either
14  * - passed to [handleCoroutineException] for [CancellableContinuation.invokeOnCancellation]
15  *   and, for [Job] instances that are coroutines, [Job.invokeOnCompletion], or
16  * - for [Job] instances that are not coroutines, simply thrown, potentially crashing unrelated code.
17  *
18  * Functions used for this must be fast, non-blocking, and thread-safe.
19  * This handler can be invoked concurrently with the surrounding code.
20  * There is no guarantee on the execution context in which the function is invoked.
21  *
22  * **Note**: This type is a part of internal machinery that supports parent-child hierarchies
23  * and allows for implementation of suspending functions that wait on the Job's state.
24  * This type should not be used in general application code.
25  */
26 // TODO: deprecate. This doesn't seem better than a simple function type.
27 public typealias CompletionHandler = (cause: Throwable?) -> Unit
28 
29 /**
30  * Essentially the same as just a function from `Throwable?` to `Unit`.
31  * The only thing implementors can do is call [invoke].
32  * The reason this abstraction exists is to allow providing a readable [toString] in the list of completion handlers
33  * as seen from the debugger.
34  * Use [UserSupplied] to create an instance from a lambda.
35  * We can't avoid defining a separate type, because on JS, you can't inherit from a function type.
36  *
37  * @see CancelHandler for a very similar interface, but used for handling cancellation and not completion.
38  */
39 internal interface InternalCompletionHandler {
40     /**
41      * Signals completion.
42      *
43      * This function:
44      * - Does not throw any exceptions.
45      *   For [Job] instances that are coroutines, exceptions thrown by this function will be caught, wrapped into
46      *   [CompletionHandlerException], and passed to [handleCoroutineException], but for those that are not coroutines,
47      *   they will just be rethrown, potentially crashing unrelated code.
48      * - Is fast, non-blocking, and thread-safe.
49      * - Can be invoked concurrently with the surrounding code.
50      * - Can be invoked from any context.
51      *
52      * The meaning of `cause` that is passed to the handler is:
53      * - It is `null` if the job has completed normally.
54      * - It is an instance of [CancellationException] if the job was cancelled _normally_.
55      *   **It should not be treated as an error**. In particular, it should not be reported to error logs.
56      * - Otherwise, the job had _failed_.
57      */
invokenull58     fun invoke(cause: Throwable?)
59 
60     /**
61      * A lambda passed from outside the coroutine machinery.
62      *
63      * See the requirements for [InternalCompletionHandler.invoke] when implementing this function.
64      */
65     class UserSupplied(private val handler: (cause: Throwable?) -> Unit) : InternalCompletionHandler {
66         /** @suppress */
67         override fun invoke(cause: Throwable?) { handler(cause) }
68 
69         override fun toString() = "InternalCompletionHandler.UserSupplied[${handler.classSimpleName}@$hexAddress]"
70     }
71 }
72