aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/scala/async/FutureSystem.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2012-11-07 20:08:33 +0100
committerJason Zaugg <jzaugg@gmail.com>2012-11-09 15:44:16 +0100
commitd434c20cfb8623a243cd30f187907bb4b199dc99 (patch)
tree3d127564874feb2ffe1633018b9afcc9bedc8d9b /src/main/scala/scala/async/FutureSystem.scala
parent7dbf0a0da4987e8fd5b223437d8f5316ff33616e (diff)
downloadscala-async-d434c20cfb8623a243cd30f187907bb4b199dc99.tar.gz
scala-async-d434c20cfb8623a243cd30f187907bb4b199dc99.tar.bz2
scala-async-d434c20cfb8623a243cd30f187907bb4b199dc99.zip
Abstract over the future implementation.
- Refactor the base macro implementation to be parameterized by a FutureSystem, which is defines the triple of types (Future, Promise, ExecutionContext) and the operations on those types (at the AST level) - Cleanup generation of ASTs, in particular, use reify more widely.
Diffstat (limited to 'src/main/scala/scala/async/FutureSystem.scala')
-rw-r--r--src/main/scala/scala/async/FutureSystem.scala138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/main/scala/scala/async/FutureSystem.scala b/src/main/scala/scala/async/FutureSystem.scala
new file mode 100644
index 0000000..64c5a66
--- /dev/null
+++ b/src/main/scala/scala/async/FutureSystem.scala
@@ -0,0 +1,138 @@
+/**
+ * Copyright (C) 2012 Typesafe Inc. <http://www.typesafe.com>
+ */
+package scala.async
+
+import reflect.macros.Context
+
+/**
+ * An abstraction over a future system.
+ *
+ * Used by the macro implementations in [[scala.async.AsyncBase]] to
+ * customize the code generation.
+ *
+ * The API mirrors that of `scala.concurrent.Future`, see the instance
+ * [[scala.async.ScalaConcurrentFutureSystem]] for an example of how
+ * to implement this.
+ */
+trait FutureSystem {
+ /** A container to receive the final value of the computation */
+ type Prom[A]
+ /** A (potentially in-progress) computation */
+ type Fut[A]
+ /** An execution context, required to create or register an on completion callback on a Future. */
+ type ExecContext
+
+ trait Ops {
+ val context: reflect.macros.Context
+
+ import context.universe._
+
+ /** Lookup the execution context, typically with an implicit search */
+ def execContext: Expr[ExecContext]
+
+ /** Create an empty promise */
+ def createProm[A: WeakTypeTag]: Expr[Prom[A]]
+
+ /** Extract a future from the given promise. */
+ def promiseToFuture[A: WeakTypeTag](prom: Expr[Prom[A]]): Expr[Fut[A]]
+
+ /** Construct a future to asynchrously compute the given expression */
+ def future[A: WeakTypeTag](a: Expr[A])(execContext: Expr[ExecContext]): Expr[Fut[A]]
+
+ /** Register an call back to run on completion of the given future */
+ def onComplete[A, U](future: Expr[Fut[A]], fun: Expr[scala.util.Try[A] => U],
+ execContext: Expr[ExecContext]): Expr[Unit]
+
+ /** Complete a promise with a value */
+ def completeProm[A](prom: Expr[Prom[A]], value: Expr[scala.util.Try[A]]): Expr[Unit]
+ }
+
+ def mkOps(c: Context): Ops {val context: c.type}
+}
+
+object ScalaConcurrentFutureSystem extends FutureSystem {
+
+ import scala.concurrent._
+
+ type Prom[A] = Promise[A]
+ type Fut[A] = Future[A]
+ type ExecContext = ExecutionContext
+
+ def mkOps(c: Context): Ops {val context: c.type} = new Ops {
+ val context: c.type = c
+
+ import context.universe._
+
+ def execContext: Expr[ExecContext] = c.Expr(c.inferImplicitValue(c.weakTypeOf[ExecutionContext]) match {
+ case EmptyTree => c.abort(c.macroApplication.pos, "Unable to resolve implicit ExecutionContext")
+ case context => context
+ })
+
+ def createProm[A: WeakTypeTag]: Expr[Prom[A]] = reify {
+ Promise[A]()
+ }
+
+ def promiseToFuture[A: WeakTypeTag](prom: Expr[Prom[A]]) = reify {
+ prom.splice.future
+ }
+
+ def future[A: WeakTypeTag](a: Expr[A])(execContext: Expr[ExecContext]) = reify {
+ Future(a.splice)(execContext.splice)
+ }
+
+ def onComplete[A, U](future: Expr[Fut[A]], fun: Expr[scala.util.Try[A] => U],
+ execContext: Expr[ExecContext]): Expr[Unit] = {
+ reify {
+ future.splice.onComplete(fun.splice)(execContext.splice)
+ context.literalUnit.splice
+ }
+ }
+
+ def completeProm[A](prom: Expr[Prom[A]], value: Expr[scala.util.Try[A]]): Expr[Unit] = reify {
+ prom.splice.complete(value.splice)
+ context.literalUnit.splice
+ }
+ }
+}
+
+/**
+ * A trivial implentation of [[scala.async.FutureSystem]] that performs computations
+ * on the current thread. Useful for testing.
+ */
+object IdentityFutureSystem extends FutureSystem {
+
+ class Prom[A](var a: A)
+
+ type Fut[A] = A
+ type ExecContext = Unit
+
+ def mkOps(c: Context): Ops {val context: c.type} = new Ops {
+ val context: c.type = c
+
+ import context.universe._
+
+ def execContext: Expr[ExecContext] = c.literalUnit
+
+ def createProm[A: WeakTypeTag]: Expr[Prom[A]] = reify {
+ new Prom(null.asInstanceOf[A])
+ }
+
+ def promiseToFuture[A: WeakTypeTag](prom: Expr[Prom[A]]) = reify {
+ prom.splice.a
+ }
+
+ def future[A: WeakTypeTag](t: Expr[A])(execContext: Expr[ExecContext]) = t
+
+ def onComplete[A, U](future: Expr[Fut[A]], fun: Expr[scala.util.Try[A] => U],
+ execContext: Expr[ExecContext]): Expr[Unit] = reify {
+ fun.splice.apply(util.Success(future.splice))
+ context.literalUnit.splice
+ }
+
+ def completeProm[A](prom: Expr[Prom[A]], value: Expr[scala.util.Try[A]]): Expr[Unit] = reify {
+ prom.splice.a = value.splice.get
+ context.literalUnit.splice
+ }
+ }
+}