Skip to content

Instantly share code, notes, and snippets.

@DRSchlaubi
Created September 21, 2021 16:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DRSchlaubi/fa4c9cdbbd8ef5218c777f1a6b2d06d8 to your computer and use it in GitHub Desktop.
Save DRSchlaubi/fa4c9cdbbd8ef5218c777f1a6b2d06d8 to your computer and use it in GitHub Desktop.
GoogleFutureUtil
package dev.schlaubi.util
import com.google.api.core.ApiFuture
import com.google.common.util.concurrent.MoreExecutors
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
import java.util.concurrent.ExecutionException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
/**
* Suspends an [ApiFuture].
*/
public suspend fun <T> ApiFuture<T>.await(): T {
// fast path when ApiFuture is already done (does not suspend)
if (isDone) {
try {
@Suppress("BlockingMethodInNonBlockingContext")
return get()
} catch (e: ExecutionException) {
throw e.cause ?: e // unwrap original cause from ExecutionException
}
}
// slow path -- suspend
return suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
this.addListener(
{
try {
cont.resume(get())
} catch (e: ExecutionException) {
cont.resumeWithException(e.cause ?: e) // unwrap original cause from ExecutionException
}
},
MoreExecutors.directExecutor()
)
cont.invokeOnCancellation {
cancel(false)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment