All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.reactive.Channel.scala Maven / Gradle / Ivy

The newest version!
package scala.reactive



import scala.collection._



/** The `Channel` is the writing end of an isolate.
 *
 *  Every isolate is associated with a channel.
 *  Unlike reactive values or signals, channels can be used
 *  in a thread-safe way -- channels can be shared between
 *  isolates and their methods called from any isolate.
 *
 *  Events cannot be directly sent to a channel.
 *  Instead, reactive values can be attached to channels.
 *  All events that a reactive value produces from that point
 *  end up in the channel.
 *
 *  {{{
 *  val r = new Reactive.Emitter[Int]
 *  c.attach(r)
 *  }}}
 *
 *  Once the `seal` method is called on the channel,
 *  no more reactive values can be attached to it.
 *
 *  {{{
 *  c.seal()
 *  c.attach(r) // this call will not attach a reactive
 *  }}}
 *
 *  The isolate stops once its channel is sealed,
 *  and all the attached reactive values unreact.
 *  This indicates no more events will arrive to the isolate.
 *
 *  @tparam T        the type of events in this channel
 */
trait Channel[@spec(Int, Long, Double) T] {

  /** Attaches a reactive value to this channel.
   *  
   *  This call has no effect if the reactive is already sealed.
   *
   *  @param r       the reactive to attach
   *  @return        this reactive channel, to chain attach calls or call `seal`
   */
  def attach(r: Reactive[T]): Channel[T]

  /** Seals this channel.
   *
   *  Once a seal is successful, no more `attach` calls will succeed.
   */
  def seal(): Channel[T]

  /** Composes this channel with a custom mapping function for the input events.
   *  
   *  Events from reactives passed to this channel are mapped inside their isolates.
   *
   *  @tparam S      type of the events the new channel will accept
   *  @param f       maps events in the resulting channel to events of the original channel
   *  @return        the new channel accepting events of type `S`
   */
  def compose[@spec(Int, Long, Double) S](f: S => T) = new Channel.Composed(this, f)

}


/** Channel implementations and creation methods.
 */
object Channel {

  private[reactive] class Composed[@spec(Int, Long, Double) T, @spec(Int, Long, Double) S]
    (val self: Channel[T], val f: S => T)
  extends Channel[S] {
    def attach(r: Reactive[S]): Channel[S] = {
      self.attach(r.map(f))
      this
    }
    def seal(): Channel[S] = {
      self.seal()
      this
    }
  }

  /** A synchronized channel.
   *
   *  Basic channel implementation for use within a single machine.
   *
   *  @tparam T        type of the channel events
   *  @param reactor   the reactor notified of this channel's events
   *  @param monitor   private monitor object used for synchronization
   */
  class Synced[@spec(Int, Long, Double) T](val reactor: Reactor[T], val monitor: util.Monitor)
  extends Channel[T] {
    private var sealedChannel = false
    private val reactives = mutable.Map[Reactive[T], Reactive.Subscription]()
    def attach(r: Reactive[T]) = monitor.synchronized {
      if (!sealedChannel) {
        if (!reactives.contains(r)) reactives(r) = r.onReaction(new Reactor[T] {
          def react(event: T) = reactor.react(event)
          def unreact() {
            monitor.synchronized { reactives.remove(r) }
            checkTerminated()
          }
        })
      }
      this
    }
    def seal(): Channel[T] = {
      monitor.synchronized { sealedChannel = true }
      checkTerminated()
      this
    }
    private[reactive] def checkTerminated() {
      val done = monitor.synchronized { sealedChannel && reactives.isEmpty }
      if (done) reactor.unreact()
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy