• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 @file:Suppress("RedundantVisibilityModifier")
6 
7 package kotlinx.coroutines.tasks
8 
9 import com.google.android.gms.tasks.CancellationTokenSource
10 import com.google.android.gms.tasks.RuntimeExecutionException
11 import com.google.android.gms.tasks.Task
12 import com.google.android.gms.tasks.TaskCompletionSource
13 import kotlinx.coroutines.CancellationException
14 import kotlinx.coroutines.CompletableDeferred
15 import kotlinx.coroutines.Deferred
16 import kotlinx.coroutines.Job
17 import kotlinx.coroutines.suspendCancellableCoroutine
18 import kotlin.coroutines.*
19 
20 /**
21  * Converts this deferred to the instance of [Task].
22  * If deferred is cancelled then resulting task will be cancelled as well.
23  */
24 public fun <T> Deferred<T>.asTask(): Task<T> {
25     val cancellation = CancellationTokenSource()
26     val source = TaskCompletionSource<T>(cancellation.token)
27 
28     invokeOnCompletion callback@{
29         if (it is CancellationException) {
30             cancellation.cancel()
31             return@callback
32         }
33 
34         val t = getCompletionExceptionOrNull()
35         if (t == null) {
36             source.setResult(getCompleted())
37         } else {
38             source.setException(t as? Exception ?: RuntimeExecutionException(t))
39         }
40     }
41 
42     return source.task
43 }
44 
45 /**
46  * Converts this task to an instance of [Deferred].
47  * If task is cancelled then resulting deferred will be cancelled as well.
48  */
asDeferrednull49 public fun <T> Task<T>.asDeferred(): Deferred<T> {
50     if (isComplete) {
51         val e = exception
52         return if (e == null) {
53             @Suppress("UNCHECKED_CAST")
54             CompletableDeferred<T>().apply { if (isCanceled) cancel() else complete(result as T) }
55         } else {
56             CompletableDeferred<T>().apply { completeExceptionally(e) }
57         }
58     }
59 
60     val result = CompletableDeferred<T>()
61     addOnCompleteListener {
62         val e = it.exception
63         if (e == null) {
64             @Suppress("UNCHECKED_CAST")
65             if (isCanceled) result.cancel() else result.complete(it.result as T)
66         } else {
67             result.completeExceptionally(e)
68         }
69     }
70     return result
71 }
72 
73 /**
74  * Awaits for completion of the task without blocking a thread.
75  *
76  * This suspending function is cancellable.
77  * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
78  * stops waiting for the completion stage and immediately resumes with [CancellationException].
79  */
awaitnull80 public suspend fun <T> Task<T>.await(): T {
81     // fast path
82     if (isComplete) {
83         val e = exception
84         return if (e == null) {
85             if (isCanceled) {
86                 throw CancellationException("Task $this was cancelled normally.")
87             } else {
88                 @Suppress("UNCHECKED_CAST")
89                 result as T
90             }
91         } else {
92             throw e
93         }
94     }
95 
96     return suspendCancellableCoroutine { cont ->
97         addOnCompleteListener {
98             val e = exception
99             if (e == null) {
100                 @Suppress("UNCHECKED_CAST")
101                 if (isCanceled) cont.cancel() else cont.resume(result as T)
102             } else {
103                 cont.resumeWithException(e)
104             }
105         }
106     }
107 }
108