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

rx.channels.Channels.scala Maven / Gradle / Ivy

The newest version!
package rx.channels

import acyclic.file
import scala.concurrent.{Promise, Future}
import java.util.concurrent.atomic.AtomicReference
import scala.annotation.tailrec

trait Source[+T]{
  def apply(): Future[T]
}

trait Sink[-T]{
  def update(t: T): Unit
}

trait Channel[T] extends Source[T] with Sink[T]

object Channel{
  /**
   * A channel that publishes any incoming events to all listeners,
   * dropping any events that come when nobody is listening.
   */
  class PubSub[T]() extends Channel[T]{
    var value: Promise[T] = null
    def apply() = {
      value = Option(value).getOrElse(Promise[T]())
      value.future
    }
    def update(t: T) = {
      value match{
        case null =>
        case v => v.success(t)
      }
      value = null
    }
  }

  /**
   * A channel that queues up events and feeds each event to a
   * single consumer. Events are buffered if there is no consumer
   * waiting for it, and consumers are buffered if there are no
   * events to consume.
   */
  class Queue[T]() extends Channel[T]{
    val queue = new AtomicReference[Either[Seq[Promise[T]],Seq[T]]](Right(Seq()))
    import queue._
    @tailrec final def update(t: T): Unit = get match {
      case r @ Right(ts) => // Queue doesn't have any waiters so enqueue this value
        if (!compareAndSet(r, Right(ts :+ t))) update(t)
      case l @ Left(Seq(p)) => // Queue has a single waiter
        if (!compareAndSet(l, Right(Seq()))) update(t)
        else p success t
      case l @ Left(p :: ps) => // Queue has multiple waiters
        if (!compareAndSet(l, Left(ps))) update(t)
        else p success t
    }

    @tailrec final def apply(): Future[T] = get match {
      case l @ Left(ps) => // Already has waiting consumers
        val p = Promise[T]()
        if (!compareAndSet(l, Left(ps :+ p))) apply()
        else p.future
      case r @ Right(Seq()) => // Empty queue, become first waiting consumer
        val p = Promise[T]()
        if (!compareAndSet(r, Left(Seq(p)))) apply()
        else p.future
      case r @ Right(t :: ts) => // Already has values. get the head
        if (!compareAndSet(r, Right(ts))) apply()
        else Future successful t
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy