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

colibri.Subject.scala Maven / Gradle / Ivy

The newest version!
package colibri

import scala.scalajs.js
import colibri.helpers._

final class ReplayLatestSubject[A] extends Observer[A] with Observable[A] {

  private val state = new PublishSubject[A]

  private var current: Option[A] = None

  def hasSubscribers: Boolean = state.hasSubscribers

  @inline def now(): Option[A] = current

  def unsafeResetState(): Unit = {
    current = None
  }

  def unsafeOnNext(value: A): Unit = {
    current = Some(value)
    state.unsafeOnNext(value)
  }

  def unsafeOnError(error: Throwable): Unit = state.unsafeOnError(error)

  def unsafeSubscribe(sink: Observer[A]): Cancelable = {
    val cancelable = state.unsafeSubscribe(sink)
    current.foreach(sink.unsafeOnNext)
    cancelable
  }
}

final class ReplayAllSubject[A] extends Observer[A] with Observable[A] {

  private val state = new PublishSubject[A]

  private val current = collection.mutable.ArrayBuffer[A]()

  def hasSubscribers: Boolean = state.hasSubscribers

  @inline def now(): Seq[A] = current.toSeq

  def unsafeResetState(): Unit = {
    current.clear()
  }

  def unsafeOnNext(value: A): Unit = {
    current += value
    state.unsafeOnNext(value)
  }

  def unsafeOnError(error: Throwable): Unit = state.unsafeOnError(error)

  def unsafeSubscribe(sink: Observer[A]): Cancelable = {
    val cancelable = state.unsafeSubscribe(sink)
    current.foreach(sink.unsafeOnNext)
    cancelable
  }
}

final class BehaviorSubject[A](private var current: A) extends Observer[A] with Observable[A] {

  private val state = new PublishSubject[A]

  def hasSubscribers: Boolean = state.hasSubscribers

  @inline def now(): A = current

  def unsafeOnNext(value: A): Unit = {
    current = value
    state.unsafeOnNext(value)
  }

  def unsafeOnError(error: Throwable): Unit = state.unsafeOnError(error)

  def unsafeSubscribe(sink: Observer[A]): Cancelable = {
    val cancelable = state.unsafeSubscribe(sink)
    sink.unsafeOnNext(current)
    cancelable
  }
}

final class PublishSubject[A] extends Observer[A] with Observable[A] {

  private var subscribers = new js.Array[Observer[A]]
  private var isRunning   = false

  def hasSubscribers: Boolean = subscribers.nonEmpty

  def unsafeOnNext(value: A): Unit = {
    isRunning = true
    subscribers.foreach(_.unsafeOnNext(value))
    isRunning = false
  }

  def unsafeOnError(error: Throwable): Unit = {
    isRunning = true
    subscribers.foreach(_.unsafeOnError(error))
    isRunning = false
  }

  def unsafeSubscribe(sink: Observer[A]): Cancelable = {
    val observer = Observer.lift(sink)
    subscribers.push(observer)
    Cancelable { () =>
      if (isRunning) subscribers = JSArrayHelper.removeElementCopied(subscribers)(observer)
      else JSArrayHelper.removeElement(subscribers)(observer)
    }
  }
}

object Subject {
  def replayLatest[O](): ReplayLatestSubject[O] = new ReplayLatestSubject[O]
  def replayAll[O](): ReplayAllSubject[O]       = new ReplayAllSubject[O]

  def behavior[O](seed: O): BehaviorSubject[O] = new BehaviorSubject[O](seed)

  def publish[O](): PublishSubject[O] = new PublishSubject[O]

  def from[A](sink: Observer[A], source: Observable[A]): Subject[A] = ProSubject.from(sink, source)

  def create[A](sinkF: A => Unit, sourceF: Observer[A] => Cancelable): Subject[A] = ProSubject.create(sinkF, sourceF)
}

object ProSubject {
  def from[I, O](sink: Observer[I], source: Observable[O]): ProSubject[I, O] = new Observer[I] with Observable[O] {
    @inline def unsafeOnNext(value: I): Unit                   = sink.unsafeOnNext(value)
    @inline def unsafeOnError(error: Throwable): Unit          = sink.unsafeOnError(error)
    @inline def unsafeSubscribe(sink: Observer[O]): Cancelable = source.unsafeSubscribe(sink)
  }

  def create[I, O](sinkF: I => Unit, sourceF: Observer[O] => Cancelable): ProSubject[I, O] = {
    val sink   = Observer.create(sinkF)
    val source = Observable.create(sourceF)
    from(sink, source)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy