1 /*
2  * Copyright 2016-2018 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.coroutines.internal.*
8 
9 /**
10  * Handler for [Job.invokeOnCompletion] and [CancellableContinuation.invokeOnCancellation].
11  *
12  * Installed handler should not throw any exceptions. If it does, they will get caught,
13  * wrapped into [CompletionHandlerException], and rethrown, potentially causing crash of unrelated code.
14  *
15  * The meaning of `cause` that is passed to the handler:
16  * * Cause is `null` when the job has completed normally.
17  * * Cause is an instance of [CancellationException] when the job was cancelled _normally_.
18  *   **It should not be treated as an error**. In particular, it should not be reported to error logs.
19  * * Otherwise, the job had _failed_.
20  *
21  * **Note**: This type is a part of internal machinery that supports parent-child hierarchies
22  * and allows for implementation of suspending functions that wait on the Job's state.
23  * This type should not be used in general application code.
24  * Implementations of `CompletionHandler` must be fast and _lock-free_.
25  */
26 public typealias CompletionHandler = (cause: Throwable?) -> Unit
27 
28 // We want class that extends LockFreeLinkedListNode & CompletionHandler but we cannot do it on Kotlin/JS,
29 // so this expect class provides us with the corresponding abstraction in a platform-agnostic way.
30 internal expect abstract class CompletionHandlerBase() : LockFreeLinkedListNode {
31     abstract fun invoke(cause: Throwable?)
32 }
33 
34 internal expect val CompletionHandlerBase.asHandler: CompletionHandler
35 
36 // More compact version of CompletionHandlerBase for CancellableContinuation with same workaround for JS
37 internal expect abstract class CancelHandlerBase() {
38     abstract fun invoke(cause: Throwable?)
39 }
40 
41 internal expect val CancelHandlerBase.asHandler: CompletionHandler
42 
43 // :KLUDGE: We have to invoke a handler in platform-specific way via `invokeIt` extension,
44 // because we play type tricks on Kotlin/JS and handler is not necessarily a function there
45 internal expect fun CompletionHandler.invokeIt(cause: Throwable?)
46 
47 internal inline fun <reified T> CompletionHandler.isHandlerOf(): Boolean = this is T
48