summaryrefslogtreecommitdiff
path: root/shared/src/main/scala/escale/syntax.scala
blob: fc4b78944089ffae55972fd1270cad1fca1cf7f6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package escale

import scala.concurrent.{ExecutionContext, Future}
import scala.language.experimental.macros

object Macros {
  import scala.reflect.macros.blackbox._

  def goImpl[A: c.WeakTypeTag](c: Context)(body: c.Expr[A])(
      execContext: c.Expr[ExecutionContext]): c.Tree = {
    import c.universe._
    val pkg = c.mirror.staticPackage("scala.async")
    q"""$pkg.Async.async($body)($execContext)"""
  }

  def asyncTakeImpl[A: c.WeakTypeTag](c: Context)(
      channel: c.Expr[Channel[A]]): c.Tree = {
    import c.universe._
    val pkg = c.mirror.staticPackage("scala.async")
    q"""$pkg.Async.await($channel.take())"""
  }

  def asyncPutImpl[A: c.WeakTypeTag](c: Context)(value: c.Expr[A]): c.Tree = {
    import c.universe._
    val pkg = c.mirror.staticPackage("scala.async")
    q"""$pkg.Async.await(${c.prefix}.channel.put($value))"""
  }

  def selectImpl(c: Context)(channels: c.Expr[Channel[_]]*): c.Tree = {
    import c.universe._
    val pkg = c.mirror.staticPackage("scala.async")
    val Channel = c.mirror.staticModule("escale.Channel")
    q"""($pkg.Async.await($Channel.select(..$channels)): @unchecked)"""
  }

}

package object syntax {

  def chan[A](capacity: Int = 0): Channel[A] = Channel[A](capacity)

  def go[A](body: => A)(implicit execContext: ExecutionContext): Future[A] =
    macro Macros.goImpl[A]

  def !<[A](channel: Channel[A]): A = macro Macros.asyncTakeImpl[A]

  implicit class ChannelOps[A](val channel: Channel[A]) extends AnyVal {
    def !<(value: A): Unit = macro Macros.asyncPutImpl[A]
  }

  def select(channels: Channel[_]*): (Channel[_], Any) = macro Macros.selectImpl

}