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 */ asDeferrednull49public 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 */ awaitnull80public 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