Created
April 13, 2013 07:28
-
-
Save markus1189/5377466 to your computer and use it in GitHub Desktop.
Simple version of events
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package reactive.event | |
import scala.collection.mutable.{Buffer,ListBuffer} | |
import Event.Callback | |
trait Event[A] { | |
protected[event] val callbacks: Buffer[Callback[A]] = ListBuffer() | |
def register(cb: Callback[A]): Event[A] = { callbacks += cb; this } | |
def += : Callback[A] => Event[A] = register | |
def +!=(action: => Unit): Event[A] = register { _ => action } | |
def and[B](other: Event[B]) = Conjunction(this,other) | |
def andThen[B](other: Event[B]) = Sequence(this,other) | |
def or(other: Event[A]) = Disjunction(this,other) | |
def until(other: Event[A]) = Until(this,other) | |
def map[B](f: A => B) = Mapping(this,f) | |
def clear() { callbacks.clear } | |
protected[event] def trigger(value: A) { callbacks.foreach(_.apply(value)) } | |
} | |
object Event { | |
type Callback[A] = A => Unit | |
} | |
/** An ExplicitEvent is only triggered if the apply or trigger method is called */ | |
class ExplicitEvent[A] protected[event] extends Event[A] { | |
def apply(a: A) { trigger(a) } | |
} | |
object ExplicitEvent { def apply[A](): ExplicitEvent[A] = new ExplicitEvent() } | |
/** A Conjunction is triggered if e1 AND e2 were triggered */ | |
class Conjunction[E1,E2] private (e1: Event[E1], e2: Event[E2]) extends Event[(E1,E2)] { | |
var value1: Option[E1] = None | |
var value2: Option[E2] = None | |
e1 register { v1 => value1 = Some(v1); checkFire() } | |
e2 register { v2 => value2 = Some(v2); checkFire() } | |
def checkFire() { | |
for ( v1 <- value1; v2 <- value2 ) { | |
trigger((v1,v2)) | |
reset() | |
} | |
} | |
def reset() { | |
value1 = None | |
value2 = None | |
} | |
} | |
object Conjunction { | |
def apply[E1,E2](e1: Event[E1], e2: Event[E2]): Event[(E1,E2)] = new Conjunction(e1,e2) | |
} | |
/** A Disjunction is triggered if e1 OR e2 is triggered */ | |
class Disjunction[E] private (ev1: Event[_ <: E], ev2: Event[_ <: E]) extends Event[E] { | |
ev1 register { trigger } | |
ev2 register { trigger } | |
} | |
object Disjunction { | |
def apply[E](e1: Event[E], e2: Event[E]): Event[E] = new Disjunction(e1,e2) | |
} | |
/** A Sequence is triggered only if e2 is triggered after an occurence of e1 */ | |
class Sequence[E1,E2] private (ev1: Event[E1], ev2: Event[E2]) extends Event[(E1,E2)] { | |
var value: Option[E1] = None | |
ev1 register { v1 => value = Some(v1) } | |
ev2 register { v2 => | |
value.foreach(trigger(_,v2)) | |
reset() | |
} | |
def reset() { value = None } | |
} | |
object Sequence { | |
def apply[E1,E2](e1: Event[E1], e2: Event[E2]): Event[(E1,E2)] = new Sequence(e1,e2) | |
} | |
/** Behaves equivalent to e1 until e2 is triggered. From that moment on, | |
* the event will not be triggered anymore | |
*/ | |
class Until[E] private (e1: Event[E], e2: Event[_]) extends Event[E] { | |
var e2Triggered = false | |
e2 +!= { e2Triggered = true } | |
e1 register { v1 => if (!e2Triggered) trigger(v1) } | |
} | |
object Until { | |
def apply[E](e1: Event[E], e2: Event[_]): Event[E] = new Until(e1,e2) | |
} | |
class Mapping[A,B] private (event: Event[A], f: A => B) extends Event[B] { | |
event register { v => trigger(f(v)) } | |
} | |
object Mapping { | |
def apply[A,B](event: Event[A], f: A => B): Event[B] = new Mapping(event,f) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment