daily pastebin goal
30%
SHARE
TWEET

Untitled

a guest Mar 19th, 2019 53 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. type TransitionListener[A] = PartialFunction[(A, A), Unit]
  2.   type EndListener[A] = PartialFunction[A, Unit]
  3.  
  4.   /** Wraps the mutable value for subscriptions */
  5.   trait Data[A] {
  6.     /** Returns the latest value */
  7.     def read: A
  8.  
  9.     /** Adds the given listener that will be invoked on every update */
  10.     def listen(code: TransitionListener[A], initialize: Boolean): Data[A]
  11.  
  12.     /** Partially projects the wrapped value with given code */
  13.     def partialMap[B](code: PartialFunction[A, B]): Data[Option[B]]
  14.  
  15.     /** Maps the wrapped value with given code */
  16.     def map[B](code: A => B): Data[B]
  17.  
  18.     /** Combines the wrapper with another one for simultaneous subscriptions */
  19.     def and[B](other: Data[B]): Data[(A, B)]
  20.  
  21.  
  22.     /** Returns the latest value */
  23.     def apply(): A = this.read
  24.  
  25.     /** Adds the given listener that will be invoked on every update */
  26.     def />>(code: TransitionListener[A]): Data[A] = {
  27.       this.listen(code, initialize = true)
  28.     }
  29.  
  30.     /** Adds the given listener that will be invoked on every update */
  31.     def />(code: EndListener[A]): Data[A] = {
  32.       val listener: TransitionListener[A] = {
  33.         case (before, after) if code.isDefinedAt(after) => code.apply(after)
  34.       }
  35.       this.listen(listener, initialize = true)
  36.     }
  37.  
  38.     /** Partially projects the wrapped value with given code */
  39.     def /~[B](code: PartialFunction[A, B]): Data[Option[B]] = this.partialMap(code)
  40.  
  41.     /** Combines the wrapper with another one for simultaneous subscriptions */
  42.     def &&[B](other: Data[B]): Data[(A, B)] = this.and(other)
  43.   }
  44.  
  45.   /** Represents the wrapper that can mutate it's value */
  46.   trait Writable[A] extends Data[A] {
  47.     /** Mutates the current value into a given one */
  48.     def write(a: A): A
  49.   }
  50.  
  51.   private class Implementation[A](default: A) extends Writable[A] with Logging {
  52.     private var value: A = default
  53.     private var listeners: List[TransitionListener[A]] = Nil
  54.  
  55.     override def partialMap[B](code: PartialFunction[A, B]): Data[Option[B]] = {
  56.       new Implementation[Option[B]](code.lift.apply(value)).mutate { source =>
  57.         this.listen({ case (before, after) =>
  58.           val current = source.read
  59.           val next = code.lift.apply(after)
  60.           if (current != next) source.write(next)
  61.         }, initialize = true)
  62.       }
  63.     }
  64.  
  65.     override def read: A = value
  66.  
  67.     override def map[B](code: A => B): Data[B] = {
  68.       new Implementation(code.apply(value)).mutate { source =>
  69.         this.listen({ case (before, after) => source.write(code.apply(after)) }, initialize = true)
  70.       }
  71.     }
  72.  
  73.     override def write(a: A): A = this.synchronized {
  74.       val before = value
  75.       val after = a
  76.       value = after
  77.       listeners.foreach { listener => listener.lift.apply(before, after) }
  78.       value
  79.     }
  80.  
  81.     override def listen(code: TransitionListener[A], initialize: Boolean): Data[A] = this.synchronized {
  82.       listeners = listeners :+ code
  83.       if (initialize) {
  84.         code.lift.apply(value, value)
  85.       }
  86.       this
  87.     }
  88.  
  89.     override def and[B](other: Data[B]): Data[(A, B)] = {
  90.       val source = new Implementation((this.read, other.read))
  91.       val handler: TransitionListener[Any] = source.synchronized {
  92.         case _ => source.write(this.read, other.read)
  93.       }
  94.  
  95.       this.listen(handler, initialize = true)
  96.       other.listen(handler, initialize = true)
  97.       source
  98.     }
  99.   }
  100.  
  101.   object Data {
  102.     /** Creates the writable data source */
  103.     def source[A](default: A): Writable[A] = new Implementation(default)
  104.  
  105.     /** Creates the writable data source */
  106.     def apply[A](default: A): Writable[A] = Data.source(default)
  107.   }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top