Skip to content

Commit c1ae1c1

Browse files
committed
Merge pull request #50 from retronym/ticket/44
More efficient round trip conversions for Futures
2 parents 2533dc1 + 9eb940d commit c1ae1c1

File tree

5 files changed

+47
-16
lines changed

5 files changed

+47
-16
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ script:
1313
- admin/build.sh
1414
scala:
1515
- 2.11.7
16-
- 2.12.0-M2
16+
# - 2.12.0-M3
1717
jdk:
1818
- oraclejdk8
1919
notifications:

build.sbt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def jwrite(dir: java.io.File)(name: String, content: String) = {
1010

1111
lazy val commonSettings = Seq(
1212
scalaVersion := "2.11.7",
13-
crossScalaVersions := List("2.11.7", "2.12.0-M2"),
13+
crossScalaVersions := List("2.11.7" /* TODO, "2.12.0-M3"*/),
1414
organization := "org.scala-lang.modules",
1515
version := "0.6.0-SNAPSHOT",
1616
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,

src/main/scala/scala/compat/java8/FutureConverters.scala

+14-12
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,14 @@ object FutureConverters {
5454
* not support the CompletableFuture interface
5555
*/
5656
def toJava[T](f: Future[T]): CompletionStage[T] = {
57-
val cf = new CF[T]
58-
implicit val ec = InternalCallbackExecutor
59-
f onComplete cf
60-
cf
57+
f match {
58+
case p: P[T] => p.wrapped
59+
case _ =>
60+
val cf = new CF[T](f)
61+
implicit val ec = InternalCallbackExecutor
62+
f onComplete cf
63+
cf
64+
}
6165
}
6266

6367
/**
@@ -71,15 +75,13 @@ object FutureConverters {
7175
* @return a Scala Future that represents the CompletionStage's completion
7276
*/
7377
def toScala[T](cs: CompletionStage[T]): Future[T] = {
74-
val p = Promise[T]()
75-
val bc = new BiConsumer[T, Throwable] {
76-
override def accept(v: T, e: Throwable): Unit = {
77-
if (e == null) p.complete(Success(v))
78-
else p.complete(Failure(e))
79-
}
78+
cs match {
79+
case cf: CF[T] => cf.wrapped
80+
case _ =>
81+
val p = new P[T](cs)
82+
cs whenComplete p
83+
p.future
8084
}
81-
cs whenComplete bc
82-
p.future
8385
}
8486

8587
/**

src/main/scala/scala/concurrent/java8/FutureConvertersImpl.scala

+12-2
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ package scala.concurrent.java8
55

66
// Located in this package to access private[concurrent] members
77

8-
import scala.concurrent.{ Future, Promise, ExecutionContext, ExecutionContextExecutorService, ExecutionContextExecutor, impl }
8+
import scala.concurrent.{ Future, ExecutionContext }
99
import java.util.concurrent._
10+
import scala.concurrent.impl.Promise.DefaultPromise
1011
import scala.util.{ Try, Success, Failure }
1112
import java.util.function.{ BiConsumer, Function JF, Consumer, BiFunction }
1213

1314
// TODO: make thie private[scala] when genjavadoc allows for that.
1415
object FuturesConvertersImpl {
1516
def InternalCallbackExecutor = Future.InternalCallbackExecutor
1617

17-
class CF[T] extends CompletableFuture[T] with (Try[T] => Unit) {
18+
class CF[T](val wrapped: Future[T]) extends CompletableFuture[T] with (Try[T] => Unit) {
1819
override def apply(t: Try[T]): Unit = t match {
1920
case Success(v) complete(v)
2021
case Failure(e) completeExceptionally(e)
@@ -84,4 +85,13 @@ object FuturesConvertersImpl {
8485

8586
override def toString: String = super[CompletableFuture].toString
8687
}
88+
89+
class P[T](val wrapped: CompletionStage[T]) extends DefaultPromise[T] with BiConsumer[T, Throwable] {
90+
override def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit = super.onSuccess(pf)
91+
92+
override def accept(v: T, e: Throwable): Unit = {
93+
if (e == null) complete(Success(v))
94+
else complete(Failure(e))
95+
}
96+
}
8797
}

src/test/java/scala/compat/java8/FutureConvertersTest.java

+19
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import static java.util.concurrent.TimeUnit.MILLISECONDS;
1313
import static java.util.concurrent.TimeUnit.SECONDS;
1414
import static org.junit.Assert.*;
15+
import static org.junit.Assert.assertSame;
1516
import static scala.compat.java8.FutureConverters.*;
1617

1718
public class FutureConvertersTest {
@@ -398,4 +399,22 @@ public void testToJavaToCompletableFutureJavaObtrudeCalledBeforeScalaComplete()
398399
// okay
399400
}
400401
}
402+
403+
@Test
404+
public void testToJavaAndBackAvoidsWrappers() {
405+
final Promise<String> p = promise();
406+
final Future<String> sf = p.future();
407+
final CompletionStage<String> cs = toJava(sf);
408+
Future<String> sf1 = toScala(cs);
409+
assertSame(sf, sf1);
410+
}
411+
412+
@Test
413+
public void testToScalaAndBackAvoidsWrappers() {
414+
final CompletableFuture<String> cf = new CompletableFuture<>();
415+
final Future<String> f = toScala(cf);
416+
CompletionStage<String> cs1 = toJava(f);
417+
assertSame(cf, cs1);
418+
419+
}
401420
}

0 commit comments

Comments
 (0)