Skip to content

Instantly share code, notes, and snippets.

@nomisRev
Last active November 9, 2020 11:55
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 nomisRev/a48bb7bb17a88add9f6390c7e33c60b5 to your computer and use it in GitHub Desktop.
Save nomisRev/a48bb7bb17a88add9f6390c7e33c60b5 to your computer and use it in GitHub Desktop.
Arrow Fx Coroutines CompletableFuture
import arrow.fx.coroutines.CancelToken
import arrow.fx.coroutines.SuspendConnection
import arrow.fx.coroutines.cancellable
import java.util.concurrent.CancellationException
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionException
import java.util.concurrent.CompletionStage
import java.util.concurrent.ExecutionException
import java.util.concurrent.Future
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.startCoroutine
fun <T> future(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend () -> T
): CompletableFuture<T> {
val future = CompletableFuture<T>()
val conn = SuspendConnection()
future.whenComplete { _, _ ->
// If the future completed externally, we should cancel the `block`
conn::cancel.startCoroutine(Continuation(EmptyCoroutineContext) { })
}
block.startCoroutine(Continuation(context + conn) {
it.fold(future::complete, future::completeExceptionally)
})
return future
}
suspend fun <A> CompletionStage<A>.await(): A =
if (this is Future<*> && isDone()) {
try {
get() as A
} catch (e: ExecutionException) {
throw e.cause ?: e // unwrap original cause from ExecutionException
}
} else cancellable { callback ->
whenComplete { res, exception ->
if (exception == null) callback(Result.success(res))
else when (exception) {
is CancellationException -> Unit
else -> callback(Result.failure((exception as? CompletionException)?.cause ?: exception))
}
}
CancelToken { (this as? CompletableFuture<A>)?.cancel(false) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment