add selfChannel and createChildren
This commit is contained in:
parent
db40d51c05
commit
8a4fca72f7
2 changed files with 94 additions and 5 deletions
|
|
@ -13,7 +13,7 @@ import scala.tools.reflect.ToolBoxError
|
|||
object ChannelSpec {
|
||||
|
||||
trait Msg
|
||||
|
||||
|
||||
trait A extends Msg
|
||||
object A extends A
|
||||
object A1 extends A
|
||||
|
|
@ -21,10 +21,10 @@ object ChannelSpec {
|
|||
|
||||
trait B extends Msg
|
||||
object B extends B
|
||||
|
||||
|
||||
trait C extends Msg
|
||||
object C extends C
|
||||
|
||||
|
||||
trait D extends Msg
|
||||
object D extends D
|
||||
|
||||
|
|
@ -49,6 +49,24 @@ object ChannelSpec {
|
|||
x ! C
|
||||
}
|
||||
}
|
||||
|
||||
// pos compile test for children
|
||||
class Children extends Channels[Parent[TNil], Channel[A, B] :=: Channel[C, D] :=: TNil] {
|
||||
val c = createChild(new Channels[Parent[A :-: TNil], Channel[B, C]:=: TNil] {
|
||||
channel[B] { case (B, s) ⇒ s ! C }
|
||||
})
|
||||
|
||||
var client: ActorRef = _
|
||||
channel[A] {
|
||||
case (A, s) ⇒ c ! B; client = sender
|
||||
}
|
||||
channel[C] {
|
||||
case (C, _) ⇒ client ! C
|
||||
}
|
||||
|
||||
createChild(new Channels[Parent[C :-: TNil], TNil])
|
||||
createChild(new Channels[Parent[A :-: C :-: TNil], TNil])
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelSpec extends AkkaSpec with ImplicitSender {
|
||||
|
|
@ -151,6 +169,36 @@ class ChannelSpec extends AkkaSpec with ImplicitSender {
|
|||
}.message must include("This ChannelRef does not support messages of type akka.channels.ChannelSpec.C.type")
|
||||
}
|
||||
|
||||
"not permit Nothing children" in {
|
||||
intercept[ToolBoxError] {
|
||||
eval("""
|
||||
|import akka.channels._
|
||||
|import ChannelSpec._
|
||||
|new Channels[Parent[TNil], Channel[A, B] :=: Channel[C, D] :=: TNil] {
|
||||
| createChild(new Channels)
|
||||
|}
|
||||
""".stripMargin)
|
||||
}.message must include("Parent argument must not be Nothing")
|
||||
}
|
||||
|
||||
"not permit too demanding children" in {
|
||||
intercept[ToolBoxError] {
|
||||
eval("""
|
||||
|import akka.channels._
|
||||
|import ChannelSpec._
|
||||
|new Channels[Parent[TNil], Channel[A, B] :=: Channel[C, D] :=: TNil] {
|
||||
| createChild(new Channels[Parent[B :-: TNil], TNil])
|
||||
|}
|
||||
""".stripMargin)
|
||||
}.message must include("This actor cannot support a child requiring channels akka.channels.ChannelSpec.B")
|
||||
}
|
||||
|
||||
"have a working selfChannel" in {
|
||||
val ref = ChannelExt(system).actorOf(new Children)
|
||||
ref ! A
|
||||
expectMsg(C)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,11 +10,16 @@ import scala.reflect.macros.Context
|
|||
import scala.reflect.runtime.universe.TypeTag
|
||||
import scala.reflect.macros.Universe
|
||||
import scala.runtime.AbstractPartialFunction
|
||||
import akka.actor.Props
|
||||
|
||||
trait Channels[P <: Parent[_], C <: ChannelList] extends Actor {
|
||||
class Channels[P <: Parent[_], C <: ChannelList: TypeTag] extends Actor {
|
||||
|
||||
import Channels._
|
||||
|
||||
def createChild[Pa <: Parent[_], Ch <: ChannelList](factory: Channels[Pa, Ch]): ChannelRef[Ch] = macro createChildImpl[C, Pa, Ch]
|
||||
|
||||
implicit val selfChannel = new ChannelRef[C](self)
|
||||
|
||||
/*
|
||||
* Warning Ugly Hack Ahead
|
||||
*
|
||||
|
|
@ -27,7 +32,7 @@ trait Channels[P <: Parent[_], C <: ChannelList] extends Actor {
|
|||
*/
|
||||
private var behavior = List.empty[Recv[Any, ChannelList]]
|
||||
|
||||
def channel[T]: Channels[P, C]#Behaviorist[T, _ <: ChannelList] = macro Channels.channelImpl[T, C, P, ChannelList]
|
||||
def channel[T]: Channels[P, C]#Behaviorist[T, _ <: ChannelList] = macro channelImpl[T, C, P, ChannelList]
|
||||
|
||||
protected def _channel[T, Ch <: ChannelList] = new Behaviorist[T, Ch]
|
||||
protected class Behaviorist[T, Ch <: ChannelList] {
|
||||
|
|
@ -87,6 +92,42 @@ object Channels {
|
|||
}
|
||||
}
|
||||
|
||||
def createChildImpl[C <: ChannelList: c.WeakTypeTag, Pa <: Parent[_]: c.WeakTypeTag, Ch <: ChannelList: c.WeakTypeTag](
|
||||
c: Context {
|
||||
type PrefixType = Channels[_, C]
|
||||
})(factory: c.Expr[Channels[Pa, Ch]]): c.Expr[ChannelRef[Ch]] = {
|
||||
|
||||
import c.universe._
|
||||
if (weakTypeOf[Pa] =:= weakTypeOf[Nothing]) {
|
||||
c.abort(c.enclosingPosition, "Parent argument must not be Nothing")
|
||||
}
|
||||
if (weakTypeOf[Ch] =:= weakTypeOf[Nothing]) {
|
||||
c.abort(c.enclosingPosition, "channel list must not be Nothing")
|
||||
}
|
||||
val missing = missingChannels(c.universe)(weakTypeOf[C], parentChannels(c.universe)(weakTypeOf[Pa]))
|
||||
if (missing.isEmpty) {
|
||||
implicit val t = c.TypeTag[Ch](c.weakTypeOf[Ch])
|
||||
reify(new ChannelRef[Ch](c.prefix.splice.context.actorOf(Props(factory.splice))))
|
||||
} else {
|
||||
c.error(c.enclosingPosition, s"This actor cannot support a child requiring channels ${missing mkString ", "}")
|
||||
reify(null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get all required channels from a Parent[_]
|
||||
*/
|
||||
final def parentChannels(u: Universe)(list: u.Type): List[u.Type] = {
|
||||
import u._
|
||||
def rec(l: u.Type, acc: List[u.Type]): List[u.Type] = l match {
|
||||
case TypeRef(_, _, ch :: tail :: Nil) ⇒ rec(tail, ch :: acc)
|
||||
case _ ⇒ acc.reverse
|
||||
}
|
||||
list match {
|
||||
case TypeRef(_, _, ch :: Nil) ⇒ rec(ch, Nil)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find all input channels matching the given message type and return a
|
||||
* list of their respective reply channels
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue