Skip to content

Commit 4ebde06

Browse files
committed
add map for selector
1 parent 065b1cc commit 4ebde06

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

src/main/scala/gopher/channels/ForeverSelectorBuilder.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ trait ForeverSelectorBuilder extends SelectorBuilder[Unit]
6565
def foreach(f:Any=>Unit):Unit =
6666
macro SelectorBuilder.foreachImpl[Unit]
6767

68+
69+
6870
/**
6971
* provide syntax for running select loop as async operation.
7072
*
@@ -77,6 +79,25 @@ trait ForeverSelectorBuilder extends SelectorBuilder[Unit]
7779
def apply(f: PartialFunction[Any,Unit]): Future[Unit] =
7880
macro SelectorBuilder.applyImpl[Unit]
7981

82+
83+
def inputBuilder[B]() = new InputSelectorBuilder[B](api)
84+
85+
/**
86+
* provide syntax for creating output channels.
87+
*{{{
88+
*
89+
* val multiplexed = for(s <- gopherApi.select.forever) yield
90+
* s match {
91+
* case x: channelA => s"A:${x}"
92+
* case x: channelB => s"B:${x}"
93+
* }
94+
*
95+
*}}}
96+
**/
97+
def map[B](f:Any=>B):Input[B] = macro SelectorBuilder.mapImpl[B]
98+
99+
def input[B](f:PartialFunction[Any,B]):Input[B] = ???
100+
80101
}
81102

82103

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package gopher.channels
2+
3+
import scala.language.experimental.macros
4+
import scala.reflect.macros.whitebox.Context
5+
import scala.reflect.api._
6+
import gopher._
7+
import gopher.util._
8+
import scala.concurrent._
9+
import scala.annotation.unchecked._
10+
11+
12+
/**
13+
* Builder for 'input' selector. Can be obtained as `gopherApi.select.input`.
14+
* or map of forever selector.
15+
*
16+
*
17+
*/
18+
class InputSelectorBuilder[T](override val api: GopherAPI) extends SelectorBuilder[T@uncheckedVariance]
19+
with Input[T]
20+
{
21+
22+
val proxy = api.makeChannel[T]()
23+
24+
def reading[A](ch: Input[A])(f: A=>T): InputSelectorBuilder[T] =
25+
macro SelectorBuilder.readingImpl[A,T,InputSelectorBuilder[T]]
26+
27+
@inline
28+
def readingWithFlowTerminationAsync[A](ch: Input[A], f: (ExecutionContext, FlowTermination[T], A) => Future[T] ): InputSelectorBuilder[T] =
29+
{
30+
def normalized(_cont:ContRead[A,T]):Option[ContRead.In[A]=>Future[Continuated[T]]] =
31+
Some(ContRead.liftIn(_cont)(a=>f(ec,selector,a) flatMap {
32+
proxy.awrite(_)
33+
} map Function.const(ContRead(normalized,ch,selector))))
34+
withReader[A](ch,normalized)
35+
}
36+
37+
/**
38+
* write x to channel if possible
39+
*/
40+
def writing[A](ch: Output[A], x: A)(f: A=>T): InputSelectorBuilder[T] =
41+
macro SelectorBuilder.writingImpl[A,T,InputSelectorBuilder[T]]
42+
43+
@inline
44+
def writingWithFlowTerminationAsync[A](ch:Output[A], x: =>A, f: (ExecutionContext, FlowTermination[T], A) => Future[T] ): this.type =
45+
withWriter[A](ch, { cw => Some(x,f(ec,cw.flowTermination,x) flatMap {
46+
x=>proxy.awrite(x)
47+
} map Function.const(cw)) })
48+
49+
def idle(body: T): InputSelectorBuilder[T] =
50+
macro SelectorBuilder.idleImpl[T,InputSelectorBuilder[T]]
51+
52+
@inline
53+
def idleWithFlowTerminationAsync(f: (ExecutionContext, FlowTermination[T]) => Future[T] ): this.type =
54+
withIdle{ sk => Some(f(ec,sk.flowTermination) flatMap(x =>
55+
proxy.awrite(x)) map(Function.const(sk)) ) }
56+
57+
def foreach(f:Any=>T):T =
58+
macro SelectorBuilder.foreachImpl[T]
59+
60+
def apply(f: PartialFunction[Any,T]): Future[T] =
61+
macro SelectorBuilder.applyImpl[T]
62+
63+
// input methods
64+
def cbread[B](f:
65+
ContRead[T,B]=>Option[
66+
ContRead.In[T]=>Future[Continuated[B]]
67+
],
68+
ft: FlowTermination[B]): Unit = proxy.cbread(f,ft)
69+
70+
71+
}
72+
73+

src/main/scala/gopher/channels/SelectorBuilder.scala

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,40 @@ object SelectorBuilder
423423
q"${builderName}.idle(${caseDef.body})"
424424
}
425425

426+
def mapImpl[T](c:Context)(f:c.Expr[Any=>T]):c.Expr[Input[T]] =
427+
{
428+
import c.universe._
429+
val builder = f.tree match {
430+
case Function(forvals,Match(choice,cases)) =>
431+
foreachBuildMatch(c)(cases)
432+
case Function(a,b) =>
433+
c.abort(f.tree.pos, "match expected in gopher select map, have: ${MacroUtil.shortString(b)} ");
434+
case _ =>
435+
c.abort(f.tree.pos, "match expected in gopher select map, have: ${MacroUtil.shortString(f.tree)}");
436+
437+
}
438+
c.Expr[Input[T]](c.untypecheck(builder))
439+
}
440+
441+
def mapBuildMatch(c:Context)(cases:List[c.universe.CaseDef]):c.Tree =
442+
{
443+
import c.universe._
444+
val bn = TermName(c.freshName)
445+
val calls = transformSelectMatch(c)(bn,cases)
446+
q"""..${q"val ${bn} = ${c.prefix}.inputBuilder()" :: calls}"""
447+
}
448+
449+
def inputImpl[T](c:Context)(f:c.Expr[PartialFunction[Any,T]]):c.Expr[Input[T]] =
450+
{
451+
import c.universe._
452+
val builder = f.tree match {
453+
case q"{case ..$cases}" =>
454+
mapBuildMatch(c)(cases)
455+
case _ => c.abort(f.tree.pos,"expected partial function with syntax case ... =>, have ${MacroUtil.shortString(f.tree)}");
456+
}
457+
c.Expr[Input[T]](c.untypecheck(builder))
458+
}
459+
426460
}
427461

428462

0 commit comments

Comments
 (0)