Skip to content

Instantly share code, notes, and snippets.

@markus1189
Created April 13, 2013 07:28
Show Gist options
  • Save markus1189/5377466 to your computer and use it in GitHub Desktop.
Save markus1189/5377466 to your computer and use it in GitHub Desktop.
Simple version of events
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