Skip to content

Commit

Permalink
Add missing overrides to FutureConvertersImpl.CF
Browse files Browse the repository at this point in the history
Not sure why I missed those initially...
  • Loading branch information
lrytz committed Apr 17, 2019
1 parent 9ce77ff commit e3d202e
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 5 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ val mimaPrereleaseHandlingSettings = Seq(
ProblemFilters.exclude[Problem]("scala.collection.convert.*"),
ProblemFilters.exclude[Problem]("scala.collection.StepperShape.*"),
ProblemFilters.exclude[Problem]("scala.jdk.*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.concurrent.impl.FutureConvertersImpl#CF.*"),
),
)

Expand Down
71 changes: 68 additions & 3 deletions src/library/scala/concurrent/impl/FutureConvertersImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,84 @@

package scala.concurrent.impl

import java.util.concurrent.{CompletableFuture, CompletionStage}
import java.util.function.BiConsumer
import java.util.concurrent.{CompletableFuture, CompletionStage, TimeUnit}
import java.util.function.{BiConsumer, BiFunction, Consumer, Function => JFunction}

import scala.concurrent.Future
import scala.concurrent.impl.Promise.DefaultPromise
import scala.util.{Failure, Success, Try}

object FutureConvertersImpl {
private[scala] object FutureConvertersImpl {
final class CF[T](val wrapped: Future[T]) extends CompletableFuture[T] with (Try[T] => Unit) {
override def apply(t: Try[T]): Unit = t match {
case Success(v) => complete(v)
case Failure(e) => completeExceptionally(e)
}

// Ensure that completions of this future cannot hold the Scala Future's completer hostage

override def thenApply[U](fn: JFunction[_ >: T, _ <: U]): CompletableFuture[U] = thenApplyAsync(fn)

override def thenAccept(fn: Consumer[_ >: T]): CompletableFuture[Void] = thenAcceptAsync(fn)

override def thenRun(fn: Runnable): CompletableFuture[Void] = thenRunAsync(fn)

override def thenCombine[U, V](cs: CompletionStage[_ <: U], fn: BiFunction[_ >: T, _ >: U, _ <: V]): CompletableFuture[V] = thenCombineAsync(cs, fn)

override def thenAcceptBoth[U](cs: CompletionStage[_ <: U], fn: BiConsumer[_ >: T, _ >: U]): CompletableFuture[Void] = thenAcceptBothAsync(cs, fn)

override def runAfterBoth(cs: CompletionStage[_], fn: Runnable): CompletableFuture[Void] = runAfterBothAsync(cs, fn)

override def applyToEither[U](cs: CompletionStage[_ <: T], fn: JFunction[_ >: T, U]): CompletableFuture[U] = applyToEitherAsync(cs, fn)

override def acceptEither(cs: CompletionStage[_ <: T], fn: Consumer[_ >: T]): CompletableFuture[Void] = acceptEitherAsync(cs, fn)

override def runAfterEither(cs: CompletionStage[_], fn: Runnable): CompletableFuture[Void] = runAfterEitherAsync(cs, fn)

override def thenCompose[U](fn: JFunction[_ >: T, _ <: CompletionStage[U]]): CompletableFuture[U] = thenComposeAsync(fn)

override def whenComplete(fn: BiConsumer[_ >: T, _ >: Throwable]): CompletableFuture[T] = whenCompleteAsync(fn)

override def handle[U](fn: BiFunction[_ >: T, Throwable, _ <: U]): CompletableFuture[U] = handleAsync(fn)

override def exceptionally(fn: JFunction[Throwable, _ <: T]): CompletableFuture[T] = {
val cf = new CompletableFuture[T]
whenCompleteAsync((t: T, e: Throwable) => { // param types for dotty b213f24ff (fixed in current dotty master, 311b8512c)
if (e == null) cf.complete(t)
else {
val n: AnyRef =
try {
fn(e).asInstanceOf[AnyRef]
} catch {
case thr: Throwable =>
cf.completeExceptionally(thr)
this
}
if (n ne this) cf.complete(n.asInstanceOf[T])
}
() // for dotty b213f24ff (fixed in current dotty master, 311b8512c)
}
)
cf
}

/**
* @inheritdoc
*
* WARNING: completing the result of this method will not complete the underlying
* Scala Future or Promise (ie, the one that that was passed to `toJava`.)
*/
override def toCompletableFuture: CompletableFuture[T] = this

override def obtrudeValue(value: T): Unit = throw new UnsupportedOperationException("obtrudeValue may not be used on the result of toJava(scalaFuture)")

override def obtrudeException(ex: Throwable): Unit = throw new UnsupportedOperationException("obtrudeException may not be used on the result of toJava(scalaFuture)")

override def get(): T = scala.concurrent.blocking(super.get())

override def get(timeout: Long, unit: TimeUnit): T = scala.concurrent.blocking(super.get(timeout, unit))

override def toString(): String = super[CompletableFuture].toString
}

final class P[T](val wrapped: CompletionStage[T]) extends DefaultPromise[T] with BiConsumer[T, Throwable] {
Expand Down
3 changes: 1 addition & 2 deletions src/library/scala/jdk/FutureConverters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ object FutureConverters {
case c: CompletionStage[T] => c
case _ =>
val cf = new CF[T](f)
implicit val ec = ExecutionContext.parasitic
f onComplete cf
f.onComplete(cf)(ExecutionContext.parasitic)
cf
}
}
Expand Down

0 comments on commit e3d202e

Please sign in to comment.