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

monix.reactive.Observable.scala Maven / Gradle / Ivy

/*
 * Copyright (c) 2014-2016 by its authors. Some rights reserved.
 * See the project homepage at: https://monix.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package monix.reactive

import java.io.{BufferedReader, InputStream, Reader}
import monix.eval.Coeval.Attempt
import monix.eval.{Coeval, Task}
import monix.execution.Ack.{Continue, Stop}
import monix.execution._
import monix.execution.cancelables.SingleAssignmentCancelable
import monix.reactive.internal.builders
import monix.reactive.observables.ObservableLike.{Operator, Transformer}
import monix.reactive.observables._
import monix.reactive.observers._
import monix.reactive.subjects._
import monix.types._
import org.reactivestreams.{Publisher => RPublisher, Subscriber => RSubscriber}
import scala.collection.mutable
import scala.concurrent.Future
import scala.concurrent.duration.{Duration, FiniteDuration}
import scala.util.control.NonFatal

/** The Observable type that implements the Reactive Pattern.
  *
  * Provides methods of subscribing to the Observable and operators
  * for combining observable sources, filtering, modifying,
  * throttling, buffering, error handling and others.
  *
  * See the available documentation at: [[https://monix.io]]
  */
trait Observable[+A] extends ObservableLike[A, Observable] { self =>
  /** Characteristic function for an `Observable` instance, that creates
    * the subscription and that eventually starts the streaming of
    * events to the given [[Observer]], being meant to be provided.
    *
    * This function is "unsafe" to call because it does not protect
    * the calls to the given [[Observer]] implementation in regards to
    * unexpected exceptions that violate the contract, therefore the
    * given instance must respect its contract and not throw any
    * exceptions when the observable calls `onNext`, `onComplete` and
    * `onError`. If it does, then the behavior is undefined.
    *
    * @see [[Observable.subscribe(observer* subscribe]].
    */
  def unsafeSubscribeFn(subscriber: Subscriber[A]): Cancelable

  def unsafeSubscribeFn(observer: Observer[A])(implicit s: Scheduler): Cancelable =
    unsafeSubscribeFn(Subscriber(observer,s))

  /** Subscribes to the stream.
    *
    * @return a subscription that can be used to cancel the streaming.
    * @see [[runWith]] for another way of consuming observables
    */
  def subscribe(subscriber: Subscriber[A]): Cancelable = {
    unsafeSubscribeFn(SafeSubscriber[A](subscriber))
  }

  /** Subscribes to the stream.
    *
    * @return a subscription that can be used to cancel the streaming.
    * @see [[runWith]] for another way of consuming observables
    */
  def subscribe(observer: Observer[A])(implicit s: Scheduler): Cancelable =
    subscribe(Subscriber(observer, s))

  /** Subscribes to the stream.
    *
    * @return a subscription that can be used to cancel the streaming.
    * @see [[runWith]] for another way of consuming observables
    */
  def subscribe(nextFn: A => Future[Ack], errorFn: Throwable => Unit, completedFn: () => Unit)
    (implicit s: Scheduler): Cancelable = {

    subscribe(new Subscriber[A] {
      implicit val scheduler = s
      def onNext(elem: A) = nextFn(elem)
      def onComplete() = completedFn()
      def onError(ex: Throwable) = errorFn(ex)
    })
  }

  /** Subscribes to the stream.
    *
    * @return a subscription that can be used to cancel the streaming.
    * @see [[runWith]] for another way of consuming observables
    */
  def subscribe(nextFn: A => Future[Ack], errorFn: Throwable => Unit)(implicit s: Scheduler): Cancelable =
    subscribe(nextFn, errorFn, () => ())

  /** Subscribes to the stream.
    *
    * @return a subscription that can be used to cancel the streaming.
    * @see [[runWith]] for another way of consuming observables
    */
  def subscribe()(implicit s: Scheduler): Cancelable =
    subscribe(elem => Continue)

  /** Subscribes to the stream.
    *
    * @return a subscription that can be used to cancel the streaming.
    * @see [[runWith]] for another way of consuming observables
    */
  def subscribe(nextFn: A => Future[Ack])(implicit s: Scheduler): Cancelable =
    subscribe(nextFn, error => s.reportFailure(error), () => ())

  /** On execution, consumes the source observable
    * with the given [[Consumer]], effectively transforming the
    * source observable into a [[monix.eval.Task Task]].
    */
  def runWith[R](f: Consumer[A,R]): Task[R] =
    f(self)

  /** Transforms the source using the given operator. */
  override def liftByOperator[B](operator: Operator[A, B]): Observable[B] =
    new Observable[B] {
      def unsafeSubscribeFn(subscriber: Subscriber[B]): Cancelable = {
        val sb = operator(subscriber)
        self.unsafeSubscribeFn(sb)
      }
    }

  /** Transforms the source using the given transformer function. */
  override def transform[B](transformer: Transformer[A, B]): Observable[B] =
    transformer(this)

  /** Wraps this Observable into a `org.reactivestreams.Publisher`.
    * See the [[http://www.reactive-streams.org/ Reactive Streams]]
    * protocol that Monix implements.
    */
  def toReactivePublisher[B >: A](implicit s: Scheduler): RPublisher[B] =
    new RPublisher[B] {
      def subscribe(subscriber: RSubscriber[_ >: B]): Unit = {
        val subscription = SingleAssignmentCancelable()
        subscription := unsafeSubscribeFn(SafeSubscriber(
          Subscriber.fromReactiveSubscriber(subscriber, subscription)
        ))
      }
    }

  /** Converts this observable into a multicast observable, useful for
    * turning a cold observable into a hot one (i.e. whose source is
    * shared by all observers).
    *
    * This operator is unsafe because `Subject` objects are stateful
    * and have to obey the `Observer` contract, meaning that they
    * shouldn't be subscribed multiple times, so they are error
    * prone. Only use if you know what you're doing, otherwise prefer
    * the safe [[Observable!.multicast multicast]] operator.
    */
  def unsafeMulticast[B >: A, R](processor: Subject[B, R])(implicit s: Scheduler): ConnectableObservable[R] =
    ConnectableObservable.unsafeMulticast(this, processor)

  /** Converts this observable into a multicast observable, useful for
    * turning a cold observable into a hot one (i.e. whose source is
    * shared by all observers).
    */
  def multicast[B >: A, R](pipe: Pipe[B, R])(implicit s: Scheduler): ConnectableObservable[R] =
    ConnectableObservable.multicast(this, pipe)

  /** Converts this observable into a multicast observable, useful for
    * turning a cold observable into a hot one (i.e. whose source is
    * shared by all observers). The underlying subject used is a
    * [[monix.reactive.subjects.PublishSubject PublishSubject]].
    */
  def publish(implicit s: Scheduler): ConnectableObservable[A] =
    unsafeMulticast(PublishSubject[A]())

  /** Returns a new Observable that multi-casts (shares) the original
    * Observable.
    */
  def share(implicit s: Scheduler): Observable[A] =
    publish.refCount

  /** Caches the emissions from the source Observable and replays them
    * in order to any subsequent Subscribers. This operator has
    * similar behavior to [[Observable!.replay(implicit* replay]]
    * except that this auto-subscribes to the source Observable rather
    * than returning a
    * [[monix.reactive.observables.ConnectableObservable ConnectableObservable]]
    * for which you must call
    * [[monix.reactive.observables.ConnectableObservable.connect connect]]
    * to activate the subscription.
    *
    * When you call cache, it does not yet subscribe to the source
    * Observable and so does not yet begin caching items. This only
    * happens when the first Subscriber calls the resulting
    * Observable's `subscribe` method.
    *
    * Note: You sacrifice the ability to cancel the origin when you
    * use the cache operator so be careful not to use this on
    * Observables that emit an infinite or very large number of items
    * that will use up memory.
    *
    * @return an Observable that, when first subscribed to, caches all of its
    *         items and notifications for the benefit of subsequent subscribers
    */
  def cache: Observable[A] =
    CachedObservable.create(self)

  /** Caches the emissions from the source Observable and replays them
    * in order to any subsequent Subscribers. This operator has
    * similar behavior to [[Observable!.replay(implicit* replay]]
    * except that this auto-subscribes to the source Observable rather
    * than returning a
    * [[monix.reactive.observables.ConnectableObservable ConnectableObservable]]
    * for which you must call
    * [[monix.reactive.observables.ConnectableObservable.connect connect]]
    * to activate the subscription.
    *
    * When you call cache, it does not yet subscribe to the source
    * Observable and so does not yet begin caching items. This only
    * happens when the first Subscriber calls the resulting
    * Observable's `subscribe` method.
    *
    * @param maxCapacity is the maximum buffer size after which old events
    *        start being dropped (according to what happens when using
    *        [[monix.reactive.subjects.ReplaySubject.createLimited[T](capacity:Int,initial* ReplaySubject.createLimited]])
    *
    * @return an Observable that, when first subscribed to, caches all of its
    *         items and notifications for the benefit of subsequent subscribers
    */
  def cache(maxCapacity: Int): Observable[A] =
    CachedObservable.create(self, maxCapacity)

  /** Converts this observable into a multicast observable, useful for
    * turning a cold observable into a hot one (i.e. whose source is
    * shared by all observers). The underlying subject used is a
    * [[monix.reactive.subjects.BehaviorSubject BehaviorSubject]].
    */
  def behavior[B >: A](initialValue: B)(implicit s: Scheduler): ConnectableObservable[B] =
    unsafeMulticast(BehaviorSubject[B](initialValue))

  /** Converts this observable into a multicast observable, useful for
    * turning a cold observable into a hot one (i.e. whose source is
    * shared by all observers). The underlying subject used is a
    * [[monix.reactive.subjects.ReplaySubject ReplaySubject]].
    */
  def replay(implicit s: Scheduler): ConnectableObservable[A] =
    unsafeMulticast(ReplaySubject[A]())

  /** Converts this observable into a multicast observable, useful for
    * turning a cold observable into a hot one (i.e. whose source is
    * shared by all observers). The underlying subject used is a
    * [[monix.reactive.subjects.ReplaySubject ReplaySubject]].
    *
    * @param bufferSize is the size of the buffer limiting the number
    *        of items that can be replayed (on overflow the head
    *        starts being dropped)
    */
  def replay(bufferSize: Int)(implicit s: Scheduler): ConnectableObservable[A] =
    unsafeMulticast(ReplaySubject.createLimited[A](bufferSize))

  /** Converts this observable into a multicast observable, useful for
    * turning a cold observable into a hot one (i.e. whose source is
    * shared by all observers). The underlying subject used is a
    * [[monix.reactive.subjects.AsyncSubject AsyncSubject]].
    */
  def publishLast(implicit s: Scheduler): ConnectableObservable[A] =
    unsafeMulticast(AsyncSubject[A]())

  /** Creates a new [[monix.execution.CancelableFuture CancelableFuture]]
    * that upon execution will signal the last generated element of the
    * source observable. Returns an `Option` because the source can be empty.
    */
  def runAsyncGetFirst(implicit s: Scheduler): CancelableFuture[Option[A]] =
    firstOptionL.runAsync(s)

  /** Creates a new [[monix.execution.CancelableFuture CancelableFuture]]
    * that upon execution will signal the last generated element of the
    * source observable. Returns an `Option` because the source can be empty.
    */
  def runAsyncGetLast(implicit s: Scheduler): CancelableFuture[Option[A]] =
    lastOptionL.runAsync(s)

  /** Creates a task that emits the total number of `onNext`
    * events that were emitted by the source.
    */
  def countL: Task[Long] =
    countF.headL

  /** Returns a `Task` which emits either `true`, in case the given predicate
    * holds for at least one item, or `false` otherwise.
    *
    * @param p is a function that evaluates the items emitted by the
    *        source, returning `true` if they pass the filter
    * @return a task that emits `true` or `false` in case
    *         the given predicate holds or not for at least one item
    */
  def existsL(p: A => Boolean): Task[Boolean] =
    findF(p).foldLeftL(false)((_, _) => true)

  /** Returns a task which emits the first item for which
    * the predicate holds.
    *
    * @param p is a function that evaluates the items emitted by the
    *        source observable, returning `true` if they pass the filter
    * @return a task that emits the first item in the source
    *         observable for which the filter evaluates as `true`
    */
  def findL(p: A => Boolean): Task[Option[A]] =
    findF(p).headOptionL

  /** Applies a binary operator to a start value and all elements of
    * the source, going left to right and returns a new `Task` that
    * upon evaluation will eventually emit the final result.
    */
  def foldLeftL[R](initial: => R)(op: (R, A) => R): Task[R] =
    foldLeftF(initial)(op).headL

  /** Folds the source observable, from start to finish, until the
    * source completes, or until the operator short-circuits the
    * process by returning `false`.
    *
    * Note that a call to [[foldLeftL]] is equivalent to this function
    * being called with an operator always returning `true` as the first
    * member of its result.
    *
    * @param op is an operator that will fold the signals of the source
    *           observable, returning either a new state along with a boolean
    *           that should become false in case the folding must be
    *           interrupted.
    */
  def foldWhileL[R](initial: => R)(op: (R,A) => (Boolean, R)): Task[R] =
    foldWhileF(initial)(op).headL

  /** Returns a `Task` that emits a single boolean, either true, in
    * case the given predicate holds for all the items emitted by the
    * source, or false in case at least one item is not verifying the
    * given predicate.
    *
    * @param p is a function that evaluates the items emitted by the source
    *        observable, returning `true` if they pass the filter
    * @return a task that emits only true or false in case the given
    *         predicate holds or not for all the items
    */
  def forAllL(p: A => Boolean): Task[Boolean] =
    existsL(e => !p(e)).map(r => !r)

  /** Creates a new [[monix.eval.Task Task]] that upon execution
    * will signal the first generated element of the source observable.
    *
    * In case the stream was empty, then the `Task` gets completed
    * in error with a `NoSuchElementException`.
    */
  def firstL: Task[A] =
    firstOrElseL(throw new NoSuchElementException("firstL on empty observable"))

  /** Creates a new [[monix.eval.Task Task]] that upon execution
    * will signal the first generated element of the source observable.
    *
    * Returns an `Option` because the source can be empty.
    */
  def firstOptionL: Task[Option[A]] =
    map(Some.apply).firstOrElseL(None)

  /** Creates a new [[monix.eval.Task Task]] that upon execution
    * will signal the first generated element of the source observable.
    *
    * In case the stream was empty, then the given default
    * gets evaluated and emitted.
    */
  def firstOrElseL[B >: A](default: => B): Task[B] =
    Task.create { (s, cb) =>
      unsafeSubscribeFn(new Subscriber.Sync[A] {
        implicit val scheduler: Scheduler = s
        private[this] var isDone = false

        def onNext(elem: A): Stop = {
          cb.onSuccess(elem)
          isDone = true
          Stop
        }

        def onError(ex: Throwable): Unit =
          if (!isDone) {
            isDone = true
            cb.onError(ex)
          }

        def onComplete(): Unit =
          if (!isDone) {
            isDone = true
            cb(Attempt(default))
          }
      })
    }

  /** Alias for [[firstOptionL]]. */
  def headOptionL: Task[Option[A]] = firstOptionL
  /** Alias for [[firstL]]. */
  def headL: Task[A] = firstL
  /** Alias for [[firstOrElseL]]. */
  def headOrElseL[B >: A](default: => B): Task[B] = firstOrElseL(default)

  /** Creates a new [[monix.eval.Task Task]] that upon execution
    * will signal the last generated element of the source observable.
    *
    * In case the stream was empty, then the given default gets
    * evaluated and emitted.
    */
  def lastOrElseL[B >: A](default: => B): Task[B] =
    Task.create { (s, cb) =>
      unsafeSubscribeFn(new Subscriber.Sync[A] {
        implicit val scheduler: Scheduler = s
        private[this] var value: A = _
        private[this] var isEmpty = true

        def onNext(elem: A): Continue = {
          if (isEmpty) isEmpty = false
          value = elem
          Continue
        }

        def onError(ex: Throwable): Unit = {
          cb.onError(ex)
        }

        def onComplete(): Unit = {
          if (isEmpty)
            cb(Attempt(default))
          else
            cb.onSuccess(value)
        }
      })
    }

  /** Returns a [[monix.eval.Task Task]] that upon execution
    * will signal the last generated element of the source observable.
    *
    * Returns an `Option` because the source can be empty.
    */
  def lastOptionL: Task[Option[A]] =
    map(Some.apply).lastOrElseL(None)

  /** Returns a [[monix.eval.Task Task]] that upon execution
    * will signal the last generated element of the source observable.
    *
    * In case the stream was empty, then the `Task` gets completed
    * in error with a `NoSuchElementException`.
    */
  def lastL: Task[A] =
    lastOrElseL(throw new NoSuchElementException("lastL"))

  /** Returns a task that emits `true` if the source observable is
    * empty, otherwise `false`.
    */
  def isEmptyL: Task[Boolean] =
    isEmptyF.headL

  /** Creates a new [[monix.eval.Task Task]] that will consume the
    * source observable and upon completion of the source it will
    * complete with `Unit`.
    */
  def completedL: Task[Unit] =
    Task.create { (s, cb) =>
      unsafeSubscribeFn(new Subscriber.Sync[A] {
        implicit val scheduler: Scheduler = s
        private[this] var isDone = false

        def onNext(elem: A): Continue = Continue
        def onError(ex: Throwable): Unit =
          if (!isDone) { isDone = true; cb.onError(ex) }
        def onComplete(): Unit =
          if (!isDone) { isDone = true; cb.onSuccess(()) }
      })
    }

  /** Takes the elements of the source and emits the maximum
    * value, after the source has completed.
    */
  def maxL[B >: A](implicit ev: Ordering[B]): Task[Option[B]] =
    maxF(ev).headOptionL

  /** Takes the elements of the source and emits the element
    * that has the maximum key value, where the key is generated by
    * the given function `f`.
    */
  def maxByL[B](f: A => B)(implicit ev: Ordering[B]): Task[Option[A]] =
    maxByF(f)(ev).headOptionL

  /** Takes the elements of the source and emits the minimum
    * value, after the source has completed.
    */
  def minL[B >: A](implicit ev: Ordering[B]): Task[Option[B]] =
    minF(ev).headOptionL

  /** Takes the elements of the source and emits the element
    * that has the minimum key value, where the key is generated by
    * the given function `f`.
    */
  def minByL[B](f: A => B)(implicit ev: Ordering[B]): Task[Option[A]] =
    minByF(f)(ev).headOptionL

  /** Returns a task that emits `false` if the source observable is
    * empty, otherwise `true`.
    */
  def nonEmptyL: Task[Boolean] =
    nonEmptyF.headL

  /** Given a source that emits numeric values, the `sum` operator sums
    * up all values and returns the result.
    */
  def sumL[B >: A](implicit B: Numeric[B]): Task[B] =
    sumF(B).headL

  /** Returns a `Task` that upon evaluation will collect all items from
    * the source in a Scala `List` and return this list instead.
    *
    * WARNING: for infinite streams the process will eventually blow up
    * with an out of memory error.
    */
  def toListL: Task[List[A]] =
    foldLeftL(mutable.ListBuffer.empty[A])(_ += _).map(_.toList)

  /** Creates a new [[monix.eval.Task Task]] that will consume the
    * source observable, executing the given callback for each element.
    */
  def foreachL(cb: A => Unit): Task[Unit] =
    Task.create { (s, onFinish) =>
      unsafeSubscribeFn(new Subscriber.Sync[A] {
        implicit val scheduler: Scheduler = s
        private[this] var isDone = false

        def onNext(elem: A): Ack = {
          try {
            cb(elem)
            Continue
          } catch {
            case NonFatal(ex) =>
              onError(ex)
              Stop
          }
        }

        def onError(ex: Throwable): Unit =
          if (!isDone) { isDone = true; onFinish.onError(ex) }
        def onComplete(): Unit =
          if (!isDone) { isDone = true; onFinish.onSuccess(()) }
      })
    }

  /** Subscribes to the source `Observable` and foreach element emitted
    * by the source it executes the given callback.
    */
  def foreach(cb: A => Unit)(implicit s: Scheduler): CancelableFuture[Unit] =
    foreachL(cb).runAsync
}

/** Observable builders.
  *
  * @define multicastDesc Creates an input channel and an output observable
  *         pair for building a [[MulticastStrategy multicast]] data-source.
  *
  *         Useful for building [[MulticastStrategy multicast]] observables
  *         from data-sources that cannot be back-pressured.
  *
  *         Prefer [[Observable.create]] when possible.
  *
  * @define fromIteratorDesc Converts any `Iterator` into an observable.
  *
  *         WARNING: reading from an `Iterator` is a destructive process.
  *         Therefore only a single subscriber is supported, the result being
  *         a single-subscriber observable. If multiple subscribers are attempted,
  *         all subscribers, except for the first one, will be terminated with a
  *         [[monix.reactive.exceptions.MultipleSubscribersException MultipleSubscribersException]].
  *
  *         Therefore, if you need a factory of data sources, from a cold source
  *         from which you can open how many iterators you want,
  *         you can use [[Observable.defer]] to build such a factory. Or you can share
  *         the resulting observable by converting it into a
  *         [[monix.reactive.observables.ConnectableObservable ConnectableObservable]]
  *         by means of [[Observable!.multicast multicast]].
  *
  * @define fromInputStreamDesc Converts a `java.io.InputStream` into an
  *         observable that will emit `Array[Byte]` elements.
  *
  *         WARNING: reading from the input stream is a destructive process.
  *         Therefore only a single subscriber is supported, the result being
  *         a single-subscriber observable. If multiple subscribers are attempted,
  *         all subscribers, except for the first one, will be terminated with a
  *         [[monix.reactive.exceptions.MultipleSubscribersException MultipleSubscribersException]].
  *
  *         Therefore, if you need a factory of data sources, from a cold source such
  *         as a `java.io.File` from which you can open how many file handles you want,
  *         you can use [[Observable.defer]] to build such a factory. Or you can share
  *         the resulting observable by converting it into a
  *         [[monix.reactive.observables.ConnectableObservable ConnectableObservable]]
  *         by means of [[Observable!.multicast multicast]].
  *
  * @define fromCharsReaderDesc Converts a `java.io.Reader` into an observable
  *         that will emit `Array[Char]` elements.
  *
  *         WARNING: reading from a reader is a destructive process.
  *         Therefore only a single subscriber is supported, the result being
  *         a single-subscriber observable. If multiple subscribers are attempted,
  *         all subscribers, except for the first one, will be terminated with a
  *         [[monix.reactive.exceptions.MultipleSubscribersException MultipleSubscribersException]].
  *
  *         Therefore, if you need a factory of data sources, from a cold source such
  *         as a `java.io.File` from which you can open how many file handles you want,
  *         you can use [[Observable.defer]] to build such a factory. Or you can share
  *         the resulting observable by converting it into a
  *         [[monix.reactive.observables.ConnectableObservable ConnectableObservable]]
  *         by means of [[Observable!.multicast multicast]].
  */
object Observable {
  /** Given a sequence of elements, builds an observable from it. */
  def apply[A](elems: A*): Observable[A] =
    Observable.fromIterable(elems)

  /** Creates an observable that doesn't emit anything, but immediately
    * calls `onComplete` instead.
    */
  def empty[A]: Observable[A] =
    builders.EmptyObservable

  /** Returns an `Observable` that on execution emits the given strict value.
    */
  def now[A](elem: A): Observable[A] =
    new builders.NowObservable(elem)

  /** Lifts an element into the `Observable` context.
    *
    * Alias for [[now]].
    */
  def pure[A](elem: A): Observable[A] =
    new builders.NowObservable(elem)

  /** Given a non-strict value, converts it into an Observable
    * that upon subscription, evaluates the expression and
    * emits a single element.
    */
  def eval[A](a: => A): Observable[A] =
    new builders.EvalAlwaysObservable(a)

  /** Alias for [[eval]]. */
  def delay[A](a: => A): Observable[A] = eval(a)

  /** Alias for [[eval]]. Deprecated. */
  @deprecated("Renamed, please use Observable.eval", since="2.0-RC12")
  def evalAlways[A](a: => A): Observable[A] = eval(a)

  /** Given a non-strict value, converts it into an Observable
    * that emits a single element and that memoizes the value
    * for subsequent invocations.
    */
  def evalOnce[A](f: => A): Observable[A] =
    new builders.EvalOnceObservable(f)

  /** Transforms a non-strict [[monix.eval.Coeval Coeval]] value
    * into an `Observable` that emits a single element.
    */
  def coeval[A](value: Coeval[A]): Observable[A] =
    value match {
      case Coeval.Now(v) => Observable.now(v)
      case Coeval.Error(ex) => Observable.raiseError(ex)
      case other => Observable.eval(other.value)
    }

  /** Lifts a non-strict value into an observable that emits a single element,
    * but upon subscription delay its evaluation by the specified timespan
    */
  def evalDelayed[A](delay: FiniteDuration, a: => A): Observable[A] =
    eval(a).delaySubscription(delay)

  /** Creates an Observable that emits an error.
    */
  def raiseError(ex: Throwable): Observable[Nothing] =
    new builders.ErrorObservable(ex)

  /** Creates an Observable that doesn't emit anything and that never
    * completes.
    */
  def never: Observable[Nothing] =
    builders.NeverObservable

  /** Forks a logical thread on executing the subscription. */
  def fork[A](fa: Observable[A]): Observable[A] =
    new builders.ForkObservable(fa)

  /** Given a subscribe function, lifts it into an [[Observable]].
    *
    * This function is unsafe to use because users have to know and apply
    * the Monix communication contract, related to thread-safety, communicating
    * demand (back-pressure) and error handling.
    *
    * Only use if you know what you're doing. Otherwise prefer [[create]].
    */
  def unsafeCreate[A](f: Subscriber[A] => Cancelable): Observable[A] =
    new builders.UnsafeCreateObservable(f)

  /** Creates an observable from a function that receives a
    * concurrent and safe
    * [[monix.reactive.observers.Subscriber.Sync Subscriber.Sync]].
    *
    * This builder represents the safe way of building observables
    * from data-sources that cannot be back-pressured.
    */
  def create[A](overflowStrategy: OverflowStrategy.Synchronous[A])
    (f: Subscriber.Sync[A] => Cancelable): Observable[A] =
    new builders.CreateObservable(overflowStrategy, f)

  /** $multicastDesc
    *
    * @param multicast is the multicast strategy to use (e.g. publish, behavior,
    *        reply, async)
    */
  def multicast[A](multicast: MulticastStrategy[A])
    (implicit s: Scheduler): (Observer.Sync[A], Observable[A]) = {

    val ref = ConcurrentSubject(multicast)
    (ref, ref)
  }

  /** $multicastDesc
    *
    * @param multicast is the multicast strategy to use (e.g. publish, behavior,
    *        reply, async)
    * @param overflow is the overflow strategy for the buffer that gets placed
    *        in front (since this will be a hot data-source that cannot be
    *        back-pressured)
    */
  def multicast[A](multicast: MulticastStrategy[A], overflow: OverflowStrategy.Synchronous[A])
    (implicit s: Scheduler): (Observer.Sync[A], Observable[A]) = {

    val ref = ConcurrentSubject(multicast, overflow)
    (ref, ref)
  }

  /** $fromIteratorDesc
    *
    * @param iterator to transform into an observable
    */
  def fromIterator[A](iterator: Iterator[A]): Observable[A] =
    new builders.IteratorAsObservable[A](iterator, Cancelable.empty)

  /** $fromIteratorDesc
    *
    * This variant of `fromIterator` takes an `onFinish` callback that
    * will be called when the streaming is finished, either with
    * `onComplete`, `onError`, when the downstream signals a `Stop` or
    * when the subscription gets canceled.
    *
    * This `onFinish` callback is guaranteed to be called only once.
    *
    * Useful for controlling resource deallocation (e.g. closing file
    * handles).
    *
    * @param iterator to transform into an observable
    * @param onFinish a callback that will be called for resource deallocation
    *        whenever the iterator is complete, or when the stream is
    *        canceled
    */
  def fromIterator[A](iterator: Iterator[A], onFinish: () => Unit): Observable[A] =
    new builders.IteratorAsObservable[A](iterator, Cancelable(onFinish))

  /** Converts any `Iterable` into an [[Observable]]. */
  def fromIterable[A](iterable: Iterable[A]): Observable[A] =
    new builders.IterableAsObservable[A](iterable)

  /** $fromInputStreamDesc
    *
    * @param in is the `InputStream` to convert into an observable
    */
  def fromInputStream(in: InputStream): Observable[Array[Byte]] =
    fromInputStream(in, chunkSize = 4096)

  /** $fromInputStreamDesc
    *
    * @param in is the `InputStream` to convert into an observable
    * @param chunkSize is the maximum length of the emitted arrays of bytes.
    *        It's also used when reading from the input stream.
    */
  def fromInputStream(in: InputStream, chunkSize: Int): Observable[Array[Byte]] =
    new builders.InputStreamObservable(in, chunkSize)

  /** $fromCharsReaderDesc
    *
    * @param in is the `Reader` to convert into an observable
    */
  def fromCharsReader(in: Reader): Observable[Array[Char]] =
    fromCharsReader(in, chunkSize = 4096)

  /** $fromCharsReaderDesc
    *
    * @param in is the `Reader` to convert into an observable
    * @param chunkSize is the maximum length of the emitted arrays of chars.
    *        It's also used when reading from the reader.
    */
  def fromCharsReader(in: Reader, chunkSize: Int): Observable[Array[Char]] =
    new builders.CharsReaderObservable(in, chunkSize)

  /** Converts a `java.io.BufferedReader` into an
    * observable that will emit `String` text lines from the input.
    *
    * Note that according to the specification of `BufferedReader`, a
    * line is considered to be terminated by any one of a line
    * feed (`\n`), a carriage return (`\r`), or a carriage return
    * followed immediately by a linefeed.
    *
    * WARNING: reading from a reader is a destructive process.
    * Therefore only a single subscriber is supported, the result being
    * a single-subscriber observable. If multiple subscribers are attempted,
    * all subscribers, except for the first one, will be terminated with a
    * [[monix.reactive.exceptions.MultipleSubscribersException MultipleSubscribersException]].
    *
    * Therefore, if you need a factory of data sources, from a cold source such
    * as a `java.io.File` from which you can open how many file handles you want,
    * you can use [[Observable.defer]] to build such a factory. Or you can share
    * the resulting observable by converting it into a
    * [[monix.reactive.observables.ConnectableObservable ConnectableObservable]]
    * by means of [[Observable!.multicast multicast]].
    *
    * @param in is the `Reader` to convert into an observable
    */
  def fromLinesReader(in: BufferedReader): Observable[String] =
    new builders.LinesReaderObservable(in)

  /** Given a `org.reactivestreams.Publisher`, converts it into a
    * Monix / Rx Observable.
    *
    * See the [[http://www.reactive-streams.org/ Reactive Streams]]
    * protocol that Monix implements.
    *
    * @see [[Observable.toReactive]] for converting an `Observable` to
    *      a reactive publisher.
    */
  def fromReactivePublisher[A](publisher: RPublisher[A]): Observable[A] =
    new builders.ReactiveObservable[A](publisher)

  /** Converts a Scala `Future` provided into an [[Observable]].
    *
    * If the created instance is a
    * [[monix.execution.CancelableFuture CancelableFuture]],
    * then it will be used for the returned
    * [[monix.execution.Cancelable Cancelable]] on `subscribe`.
    */
  def fromFuture[A](factory: => Future[A]): Observable[A] =
    new builders.FutureAsObservable(factory)

  /** Converts any [[monix.eval.Task Task]] into an [[Observable]]. */
  def fromTask[A](task: Task[A]): Observable[A] =
    new builders.TaskAsObservable(task)

  /** Returns a new observable that creates a sequence from the
    * given factory on each subscription.
    */
  def defer[A](fa: => Observable[A]): Observable[A] =
    new builders.DeferObservable(fa)

  /** Alias for [[defer]]. */
  def suspend[A](fa: => Observable[A]): Observable[A] = defer(fa)

  /** Builds a new observable from a strict `head` and a lazily
    * evaluated head.
    */
  def cons[A](head: A, tail: Observable[A]): Observable[A] =
    new builders.ConsObservable[A](head, tail)

  /** Creates a new observable from this observable and another given
    * observable by interleaving their items into a strictly alternating sequence.
    *
    * So the first item emitted by the new observable will be the item emitted by
    * `self`, the second item will be emitted by the other observable, and so forth;
    * when either `self` or `other` calls `onCompletes`, the items will then be
    * directly coming from the observable that has not completed; when `onError` is
    * called by either `self` or `other`, the new observable will call `onError` and halt.
    *
    * See [[merge]] for a more relaxed alternative that doesn't
    * emit items in strict alternating sequence.
    */
  def interleave2[A](oa1: Observable[A], oa2: Observable[A]): Observable[A] =
    new builders.Interleave2Observable(oa1, oa2)

  /** Creates an Observable that emits auto-incremented natural numbers
    * (longs) spaced by a given time interval. Starts from 0 with no
    * delay, after which it emits incremented numbers spaced by the
    * `period` of time. The given `period` of time acts as a fixed
    * delay between successive events.
    *
    * @param delay the delay between 2 successive events
    */
  def intervalWithFixedDelay(delay: FiniteDuration): Observable[Long] =
    new builders.IntervalFixedDelayObservable(Duration.Zero, delay)

  /** Creates an Observable that emits auto-incremented natural numbers
    * (longs) spaced by a given time interval. Starts from 0 with no
    * delay, after which it emits incremented numbers spaced by the
    * `period` of time. The given `period` of time acts as a fixed
    * delay between successive events.
    *
    * @param initialDelay is the delay to wait before emitting the first event
    * @param delay the time to wait between 2 successive events
    */
  def intervalWithFixedDelay(initialDelay: FiniteDuration, delay: FiniteDuration): Observable[Long] =
    new builders.IntervalFixedDelayObservable(initialDelay, delay)

  /** Creates an Observable that emits auto-incremented natural numbers
    * (longs) spaced by a given time interval. Starts from 0 with no
    * delay, after which it emits incremented numbers spaced by the
    * `period` of time. The given `period` of time acts as a fixed
    * delay between successive events.
    *
    * @param delay the delay between 2 successive events
    */
  def interval(delay: FiniteDuration): Observable[Long] =
    intervalWithFixedDelay(delay)

  /** Creates an Observable that emits auto-incremented natural numbers
    * (longs) at a fixed rate, as given by the specified `period`. The
    * time it takes to process an `onNext` event gets subtracted from
    * the specified `period` and thus the created observable tries to
    * emit events spaced by the given time interval, regardless of how
    * long the processing of `onNext` takes.
    *
    * @param period the period between 2 successive `onNext` events
    */
  def intervalAtFixedRate(period: FiniteDuration): Observable[Long] =
    new builders.IntervalFixedRateObservable(Duration.Zero, period)

  /** Creates an Observable that emits auto-incremented natural numbers
    * (longs) at a fixed rate, as given by the specified `period`. The
    * time it takes to process an `onNext` event gets subtracted from
    * the specified `period` and thus the created observable tries to
    * emit events spaced by the given time interval, regardless of how
    * long the processing of `onNext` takes.
    *
    * This version of the `intervalAtFixedRate` allows specifying an
    * `initialDelay` before events start being emitted.
    *
    * @param initialDelay is the initial delay before emitting the first event
    * @param period the period between 2 successive `onNext` events
    */
  def intervalAtFixedRate(initialDelay: FiniteDuration, period: FiniteDuration): Observable[Long] =
    new builders.IntervalFixedRateObservable(initialDelay, period)

  /** Creates an Observable that continuously emits the given ''item'' repeatedly.
    */
  def repeat[A](elems: A*): Observable[A] =
    new builders.RepeatObservable(elems:_*)

  /** Repeats the execution of the given `task`, emitting
    * the results indefinitely.
    */
  def repeatEval[A](task: => A): Observable[A] =
    new builders.RepeatEvalObservable(task)

  /** Creates an Observable that emits items in the given range.
    *
    * @param from the range start
    * @param until the range end
    * @param step increment step, either positive or negative
    */
  def range(from: Long, until: Long, step: Long = 1L): Observable[Long] =
    new builders.RangeObservable(from, until, step)

  /** Given an initial state and a generator function that produces the
    * next state and the next element in the sequence, creates an
    * observable that keeps generating elements produced by our
    * generator function.
    */
  def fromStateAction[S, A](f: S => (A, S))(initialState: => S): Observable[A] =
    new builders.StateActionObservable(initialState, f)

  /** Given an initial state and a generator function that produces the
    * next state and the next element in the sequence, creates an
    * observable that keeps generating elements produced by our
    * generator function.
    */
  def fromAsyncStateAction[S, A](f: S => Task[(A, S)])(initialState: => S): Observable[A] =
    new builders.AsyncStateActionObservable(initialState, f)

  /** Wraps this Observable into a `org.reactivestreams.Publisher`.
    * See the [[http://www.reactive-streams.org/ Reactive Streams]]
    * protocol that Monix implements.
    */
  def toReactive[A](source: Observable[A])(implicit s: Scheduler): RPublisher[A] =
    source.toReactivePublisher[A](s)

  /** Create an Observable that repeatedly emits the given `item`, until
    * the underlying Observer cancels.
    */
  def timerRepeated[A](initialDelay: FiniteDuration, period: FiniteDuration, unit: A): Observable[A] =
    new builders.RepeatedValueObservable[A](initialDelay, period, unit)

  /** Concatenates the given list of ''observables'' into a single observable.
    */
  def flatten[A](sources: Observable[A]*): Observable[A] =
    Observable.fromIterable(sources).concat

  /** Concatenates the given list of ''observables'' into a single
    * observable.  Delays errors until the end.
    */
  def flattenDelayError[A](sources: Observable[A]*): Observable[A] =
    Observable.fromIterable(sources).concatDelayError

  /** Merges the given list of ''observables'' into a single observable.
    */
  def merge[A](sources: Observable[A]*)
    (implicit os: OverflowStrategy[A] = OverflowStrategy.Default): Observable[A] =
    Observable.fromIterable(sources).mergeMap(identity)(os)

  /** Merges the given list of ''observables'' into a single observable.
    * Delays errors until the end.
    */
  def mergeDelayError[A](sources: Observable[A]*)
    (implicit os: OverflowStrategy[A] = OverflowStrategy.Default): Observable[A] =
    Observable.fromIterable(sources).mergeMapDelayErrors(identity)(os)

  /** Concatenates the given list of ''observables'' into a single
    * observable.
    */
  def concat[A](sources: Observable[A]*): Observable[A] =
    Observable.fromIterable(sources).concatMap[A](identity)

  /** Concatenates the given list of ''observables'' into a single observable.
    * Delays errors until the end.
    */
  def concatDelayError[A](sources: Observable[A]*): Observable[A] =
    Observable.fromIterable(sources).concatMapDelayError[A](identity)

  /** Given a sequence of observables, builds an observable
    * that emits the elements of the most recently emitted
    * observable.
    */
  def switch[A](sources: Observable[A]*): Observable[A] =
    Observable.fromIterable(sources).switch

  /** Creates a new observable from two observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap2]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    */
  def zip2[A1,A2](oa1: Observable[A1], oa2: Observable[A2]): Observable[(A1,A2)] =
    new builders.Zip2Observable[A1,A2,(A1,A2)](oa1,oa2)((a1,a2) => (a1,a2))

  /** Creates a new observable from two observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap2]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    *
    * @param f is the mapping function applied over the generated pairs
    */
  def zipMap2[A1,A2,R](oa1: Observable[A1], oa2: Observable[A2])(f: (A1,A2) => R): Observable[R] =
    new builders.Zip2Observable[A1,A2,R](oa1,oa2)(f)

  /** Creates a new observable from three observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap3]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    */
  def zip3[A1,A2,A3](oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3]): Observable[(A1,A2,A3)] =
    new builders.Zip3Observable(oa1,oa2,oa3)((a1,a2,a3) => (a1,a2,a3))

  /** Creates a new observable from three observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap3]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    *
    * @param f is the mapping function applied over the generated pairs
    */
  def zipMap3[A1,A2,A3,R](oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3])
    (f: (A1,A2,A3) => R): Observable[R] =
    new builders.Zip3Observable(oa1,oa2,oa3)(f)

  /** Creates a new observable from four observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap4]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    */
  def zip4[A1,A2,A3,A4]
    (oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3], oa4: Observable[A4]): Observable[(A1,A2,A3,A4)] =
    new builders.Zip4Observable(oa1,oa2,oa3,oa4)((a1,a2,a3,a4) => (a1,a2,a3,a4))

  /** Creates a new observable from four observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap4]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    *
    * @param f is the mapping function applied over the generated pairs
    */
  def zipMap4[A1,A2,A3,A4,R]
    (oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3], oa4: Observable[A4])
    (f: (A1,A2,A3,A4) => R): Observable[R] =
    new builders.Zip4Observable(oa1,oa2,oa3,oa4)(f)

  /** Creates a new observable from five observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap5]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    */
  def zip5[A1,A2,A3,A4,A5](
    oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3],
    oa4: Observable[A4], oa5: Observable[A5]): Observable[(A1,A2,A3,A4,A5)] =
    new builders.Zip5Observable(oa1,oa2,oa3,oa4,oa5)((a1,a2,a3,a4,a5) => (a1,a2,a3,a4,a5))

  /** Creates a new observable from five observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap5]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    *
    * @param f is the mapping function applied over the generated pairs
    */
  def zipMap5[A1,A2,A3,A4,A5,R]
    (oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3],
     oa4: Observable[A4], oa5: Observable[A5])
    (f: (A1,A2,A3,A4,A5) => R): Observable[R] =
    new builders.Zip5Observable(oa1,oa2,oa3,oa4,oa5)(f)

  /** Creates a new observable from five observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap5]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    */
  def zip6[A1,A2,A3,A4,A5,A6](
    oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3],
    oa4: Observable[A4], oa5: Observable[A5], oa6: Observable[A6]): Observable[(A1,A2,A3,A4,A5,A6)] =
    new builders.Zip6Observable(oa1,oa2,oa3,oa4,oa5,oa6)((a1,a2,a3,a4,a5,a6) => (a1,a2,a3,a4,a5,a6))

  /** Creates a new observable from five observable sequences
    * by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the result
    * of the function applied to the first items emitted by each of
    * the source observables; the second item emitted by the new observable
    * will be the result of the function applied to the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap5]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    *
    * @param f is the mapping function applied over the generated pairs
    */
  def zipMap6[A1,A2,A3,A4,A5,A6,R]
    (oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3],
     oa4: Observable[A4], oa5: Observable[A5], oa6: Observable[A6])
    (f: (A1,A2,A3,A4,A5,A6) => R): Observable[R] =
    new builders.Zip6Observable(oa1,oa2,oa3,oa4,oa5,oa6)(f)

  /** Given an observable sequence, it [[Observable!.zip zips]] them
    * together returning a new observable that generates sequences.
    */
  def zipList[A](sources: Observable[A]*): Observable[Seq[A]] = {
    if (sources.isEmpty) Observable.empty
    else {
      val seed = sources.head.map(t => Vector(t))
      sources.tail.foldLeft(seed) { (acc, obs) =>
        acc.zipMap(obs)((seq, elem) => seq :+ elem)
      }
    }
  }

  @deprecated("Renamed to Observable.zipMap2", since="2.0-RC12")
  def zipWith2[A1,A2,R](fa1: Observable[A1], fa2: Observable[A2])(f: (A1,A2) => R): Observable[R] =
    zipMap2(fa1, fa2)(f)

  @deprecated("Renamed to Observable.zipMap3", since="2.0-RC12")
  def zipWith3[A1,A2,A3,R](fa1: Observable[A1], fa2: Observable[A2], fa3: Observable[A3])(f: (A1,A2,A3) => R): Observable[R] =
    zipMap3(fa1, fa2, fa3)(f)

  @deprecated("Renamed to Observable.zipMap4", since="2.0-RC12")
  def zipWith4[A1,A2,A3,A4,R](fa1: Observable[A1], fa2: Observable[A2], fa3: Observable[A3], fa4: Observable[A4])(f: (A1,A2,A3,A4) => R): Observable[R] =
    zipMap4(fa1, fa2, fa3, fa4)(f)

  @deprecated("Renamed to Observable.zipMap5", since="2.0-RC12")
  def zipWith5[A1,A2,A3,A4,A5,R](fa1: Observable[A1], fa2: Observable[A2], fa3: Observable[A3], fa4: Observable[A4], fa5: Observable[A5])(f: (A1,A2,A3,A4,A5) => R): Observable[R] =
    zipMap5(fa1, fa2, fa3, fa4, fa5)(f)

  @deprecated("Renamed to Observable.zipMap6", since="2.0-RC12")
  def zipWith6[A1,A2,A3,A4,A5,A6,R](fa1: Observable[A1], fa2: Observable[A2], fa3: Observable[A3], fa4: Observable[A4], fa5: Observable[A5], fa6: Observable[A6])(f: (A1,A2,A3,A4,A5,A6) => R): Observable[R] =
    zipMap6(fa1, fa2, fa3, fa4, fa5, fa6)(f)

  /** Creates a combined observable from 2 source observables.
    *
    * This operator behaves in a similar way to [[zip2]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatest2[A1,A2](oa1: Observable[A1], oa2: Observable[A2]): Observable[(A1, A2)] =
    new builders.CombineLatest2Observable[A1,A2,(A1,A2)](oa1,oa2)((a1,a2) => (a1,a2))

  /** Creates a combined observable from 2 source observables.
    *
    * This operator behaves in a similar way to [[zipMap2]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatestMap2[A1,A2,R](oa1: Observable[A1], oa2: Observable[A2])
    (f: (A1,A2) => R): Observable[R] =
    new builders.CombineLatest2Observable[A1,A2,R](oa1,oa2)(f)

  /** Creates a combined observable from 3 source observables.
    *
    * This operator behaves in a similar way to [[zip3]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatest3[A1,A2,A3](
    oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3]): Observable[(A1,A2,A3)] =
    new builders.CombineLatest3Observable(oa1,oa2,oa3)((a1,a2,a3) => (a1,a2,a3))

  /** Creates a combined observable from 3 source observables.
    *
    * This operator behaves in a similar way to [[zipMap3]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatestMap3[A1,A2,A3,R](a1: Observable[A1], a2: Observable[A2], a3: Observable[A3])
    (f: (A1,A2,A3) => R): Observable[R] =
    new builders.CombineLatest3Observable[A1,A2,A3,R](a1,a2,a3)(f)

  /** Creates a combined observable from 4 source observables.
    *
    * This operator behaves in a similar way to [[zip4]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatest4[A1,A2,A3,A4](
    oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3],
    oa4: Observable[A4]): Observable[(A1,A2,A3,A4)] =
    new builders.CombineLatest4Observable(oa1,oa2,oa3,oa4)((a1,a2,a3,a4) => (a1,a2,a3,a4))

  /** Creates a combined observable from 4 source observables.
    *
    * This operator behaves in a similar way to [[zipMap4]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatestMap4[A1,A2,A3,A4,R]
    (a1: Observable[A1], a2: Observable[A2], a3: Observable[A3], a4: Observable[A4])
    (f: (A1,A2,A3,A4) => R): Observable[R] =
    new builders.CombineLatest4Observable[A1,A2,A3,A4,R](a1,a2,a3,a4)(f)

  /** Creates a combined observable from 5 source observables.
    *
    * This operator behaves in a similar way to [[zip5]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatest5[A1,A2,A3,A4,A5](
    oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3],
    oa4: Observable[A4], oa5: Observable[A5]): Observable[(A1,A2,A3,A4,A5)] =
    new builders.CombineLatest5Observable(oa1,oa2,oa3,oa4,oa5)((a1,a2,a3,a4,a5) => (a1,a2,a3,a4,a5))

  /** Creates a combined observable from 5 source observables.
    *
    * This operator behaves in a similar way to [[zipMap5]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatestMap5[A1,A2,A3,A4,A5,R]
    (a1: Observable[A1], a2: Observable[A2], a3: Observable[A3], a4: Observable[A4], a5: Observable[A5])
    (f: (A1,A2,A3,A4,A5) => R): Observable[R] =
    new builders.CombineLatest5Observable[A1,A2,A3,A4,A5,R](a1,a2,a3,a4,a5)(f)

  /** Creates a combined observable from 6 source observables.
    *
    * This operator behaves in a similar way to [[zip6]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatest6[A1,A2,A3,A4,A5,A6](
    oa1: Observable[A1], oa2: Observable[A2], oa3: Observable[A3],
    oa4: Observable[A4], oa5: Observable[A5], oa6: Observable[A6]): Observable[(A1,A2,A3,A4,A5,A6)] =
    new builders.CombineLatest6Observable(oa1,oa2,oa3,oa4,oa5,oa6)((a1,a2,a3,a4,a5,a6) => (a1,a2,a3,a4,a5,a6))

  /** Creates a combined observable from 6 source observables.
    *
    * This operator behaves in a similar way to [[zipMap6]],
    * but while `zip` emits items only when all of the zipped source
    * observables have emitted a previously unzipped item, `combine`
    * emits an item whenever any of the source Observables emits an
    * item (so long as each of the source Observables has emitted at
    * least one item).
    */
  def combineLatestMap6[A1,A2,A3,A4,A5,A6,R]
    (a1: Observable[A1], a2: Observable[A2], a3: Observable[A3],
     a4: Observable[A4], a5: Observable[A5], a6: Observable[A6])
    (f: (A1,A2,A3,A4,A5,A6) => R): Observable[R] =
    new builders.CombineLatest6Observable[A1,A2,A3,A4,A5,A6,R](a1,a2,a3,a4,a5,a6)(f)

  /** Given an observable sequence, it combines them together
    * (using [[combineLatestMap2 combineLatest]])
    * returning a new observable that generates sequences.
    */
  def combineLatestList[A](sources: Observable[A]*): Observable[Seq[A]] = {
    if (sources.isEmpty) Observable.empty
    else {
      val seed = sources.head.map(t => Vector(t))
      sources.tail.foldLeft(seed) { (acc, obs) =>
        acc.combineLatestMap(obs) { (seq, elem) => seq :+ elem }
      }
    }
  }

  @deprecated("Renamed to Observable.combineLatestMap2", since="2.0-RC12")
  def combineLatestWith2[A1,A2,R](fa1: Observable[A1], fa2: Observable[A2])(f: (A1,A2) => R): Observable[R] =
    combineLatestMap2(fa1, fa2)(f)

  @deprecated("Renamed to Observable.combineLatestMap3", since="2.0-RC12")
  def combineLatestWith3[A1,A2,A3,R](fa1: Observable[A1], fa2: Observable[A2], fa3: Observable[A3])(f: (A1,A2,A3) => R): Observable[R] =
    combineLatestMap3(fa1, fa2, fa3)(f)

  @deprecated("Renamed to Observable.combineLatestMap4", since="2.0-RC12")
  def combineLatestWith4[A1,A2,A3,A4,R](fa1: Observable[A1], fa2: Observable[A2], fa3: Observable[A3], fa4: Observable[A4])(f: (A1,A2,A3,A4) => R): Observable[R] =
    combineLatestMap4(fa1, fa2, fa3, fa4)(f)

  @deprecated("Renamed to Observable.combineLatestMap5", since="2.0-RC12")
  def combineLatestWith5[A1,A2,A3,A4,A5,R](fa1: Observable[A1], fa2: Observable[A2], fa3: Observable[A3], fa4: Observable[A4], fa5: Observable[A5])(f: (A1,A2,A3,A4,A5) => R): Observable[R] =
    combineLatestMap5(fa1, fa2, fa3, fa4, fa5)(f)

  @deprecated("Renamed to Observable.combineLatestMap6", since="2.0-RC12")
  def combineLatestWith6[A1,A2,A3,A4,A5,A6,R](fa1: Observable[A1], fa2: Observable[A2], fa3: Observable[A3], fa4: Observable[A4], fa5: Observable[A5], fa6: Observable[A6])(f: (A1,A2,A3,A4,A5,A6) => R): Observable[R] =
    combineLatestMap6(fa1, fa2, fa3, fa4, fa5, fa6)(f)

  /** Given a list of source Observables, emits all of the items from
    * the first of these Observables to emit an item or to complete,
    * and cancel the rest.
    */
  def firstStartedOf[A](source: Observable[A]*): Observable[A] =
    new builders.FirstStartedObservable(source: _*)

  /** Implicit type-class instances for [[Observable]]. */
  implicit val typeClassInstances: TypeClassInstances = new TypeClassInstances

  /** Type-class instances for [[Observable]]. */
  class TypeClassInstances extends DeferrableClass[Observable]
    with MemoizableClass[Observable] with RecoverableClass[Observable,Throwable]
    with MonadFilterClass[Observable] with MonoidKClass[Observable]
    with CoflatMapClass[Observable] {

    override def pure[A](a: A): Observable[A] = Observable.now(a)
    override def defer[A](fa: => Observable[A]): Observable[A] = Observable.suspend(fa)
    override def eval[A](a: => A): Observable[A] = Observable.eval(a)
    override def evalOnce[A](a: => A): Observable[A] = Observable.evalOnce(a)
    override def memoize[A](fa: Observable[A]): Observable[A] = fa.cache

    override def combineK[A](x: Observable[A], y: Observable[A]): Observable[A] =
      x ++ y
    override def flatMap[A, B](fa: Observable[A])(f: (A) => Observable[B]): Observable[B] =
      fa.flatMap(f)
    override def flatten[A](ffa: Observable[Observable[A]]): Observable[A] =
      ffa.flatten
    override def coflatMap[A, B](fa: Observable[A])(f: (Observable[A]) => B): Observable[B] =
      Observable.eval(f(fa))
    override def ap[A, B](ff: Observable[(A) => B])(fa: Observable[A]): Observable[B] =
      for (f <- ff; a <- fa) yield f(a)
    override def map2[A, B, Z](fa: Observable[A], fb: Observable[B])(f: (A, B) => Z): Observable[Z] =
      for (a <- fa; b <- fb) yield f(a,b)
    override def map[A, B](fa: Observable[A])(f: (A) => B): Observable[B] =
      fa.map(f)
    override def raiseError[A](e: Throwable): Observable[A] =
      Observable.raiseError(e)
    override def onErrorHandle[A](fa: Observable[A])(f: (Throwable) => A): Observable[A] =
      fa.onErrorHandle(f)
    override def onErrorHandleWith[A](fa: Observable[A])(f: (Throwable) => Observable[A]): Observable[A] =
      fa.onErrorHandleWith(f)
    override def onErrorRecover[A](fa: Observable[A])(pf: PartialFunction[Throwable, A]): Observable[A] =
      fa.onErrorRecover(pf)
    override def onErrorRecoverWith[A](fa: Observable[A])(pf: PartialFunction[Throwable, Observable[A]]): Observable[A] =
      fa.onErrorRecoverWith(pf)
    override def empty[A]: Observable[A] =
      Observable.empty[A]
    override def filter[A](fa: Observable[A])(f: (A) => Boolean): Observable[A] =
      fa.filter(f)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy