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

monix.reactive.observables.ObservableLike.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.observables

import java.io.PrintStream
import monix.execution.Scheduler
import monix.execution.cancelables.BooleanCancelable
import monix.reactive.OverflowStrategy.Synchronous
import monix.reactive.exceptions.UpstreamTimeoutException
import monix.reactive.internal.builders.{CombineLatest2Observable, Interleave2Observable, Zip2Observable}
import monix.reactive.internal.operators._
import monix.reactive.observables.ObservableLike.{Operator, Transformer}
import monix.reactive.observers.Subscriber
import monix.reactive.{Notification, Observable, OverflowStrategy, Pipe}
import scala.concurrent.duration.FiniteDuration

/** Defines the available operations for observable-like instances.
  *
  * @define concatMergeDifference The difference between the `concat` operation
  *         and `merge`is that `concat` cares about the ordering of sequences
  *         (e.g. all items emitted by the first observable in the sequence
  *         will come before the elements emitted by the second observable),
  *         whereas `merge` doesn't care about that (elements get
  *         emitted as they come). Because of back-pressure applied to
  *         observables, `concat` is safe to use in all contexts, whereas
  *         `merge` requires buffering.
  * @define concatDescription Concatenates the sequence
  *         of observables emitted by the source into one observable,
  *         without any transformation.
  *
  *         You can combine the items emitted by multiple observables
  *         so that they act like a single sequence by using this
  *         operator.
  *
  *         $concatMergeDifference
  * @define delayErrorsDescription This version is reserving onError
  *         notifications until all of the observables complete and only
  *         then passing the issued errors(s) downstream. Note that
  *         the streamed error is a
  *         [[monix.reactive.exceptions.CompositeException CompositeException]],
  *         since multiple errors from multiple streams can happen.
  * @define concatReturn an observable that emits items that are the result of
  *         flattening the items emitted by the observables emitted by the source
  * @define switchDescription Convert an observable that emits observables
  *         into a single observable that emits the items emitted by
  *         the most-recently-emitted of those observables.
  * @define switchMapDescription Returns a new observable that emits the items
  *         emitted by the observable most recently generated by the
  *         mapping function.
  * @define overflowStrategyParam the [[OverflowStrategy overflow strategy]]
  *         used for buffering, which specifies what to do in case
  *         we're dealing with a slow consumer - should an unbounded
  *         buffer be used, should back-pressure be applied, should
  *         the pipeline drop newer or older events, should it drop
  *         the whole buffer? See [[OverflowStrategy]] for more
  *         details.
  * @define defaultOverflowStrategy this operation needs to do buffering
  *         and by not specifying an [[OverflowStrategy]], the
  *         [[OverflowStrategy.Default default strategy]] is being
  *         used.
  * @define mergeMapDescription Creates a new observable by applying a
  *         function that you supply to each item emitted by the
  *         source observable, where that function returns an
  *         observable, and then merging those resulting observable
  *         and emitting the results of this merger.
  *
  *         The difference between this and `concatMap` is that
  *         `concatMap` cares about ordering of emitted
  *         items (e.g. all items emitted by the first observable in
  *         the sequence will come before the elements emitted by the
  *         second observable), whereas `merge` doesn't care about
  *         that (elements get emitted as they come). Because of
  *         back-pressure applied to observables, the `concat` operation
  *         is safe to use in all contexts, whereas `merge` requires
  *         buffering.
  * @define mergeMapReturn an observable that emits the result of applying the
  *         transformation function to each item emitted by the source
  *         observable and merging the results of the observables
  *         obtained from this transformation.
  * @define mergeDescription Merges the sequence of Observables emitted by
  *         the source into one Observable, without any transformation.
  *
  *         You can combine the items emitted by multiple Observables
  *         so that they act like a single Observable by using this
  *         operator.
  * @define mergeReturn an Observable that emits items that are the
  *         result of flattening the items emitted by the Observables
  *         emitted by `this`.
  * @define asyncBoundaryDescription Forces a buffered asynchronous boundary.
  *
  *         Internally it wraps the observer implementation given to
  *         `onSubscribe` into a
  *         [[monix.reactive.observers.BufferedSubscriber BufferedSubscriber]].
  *
  *         Normally Monix's implementation guarantees that events are
  *         not emitted concurrently, and that the publisher MUST NOT
  *         emit the next event without acknowledgement from the
  *         consumer that it may proceed, however for badly behaved
  *         publishers, this wrapper provides the guarantee that the
  *         downstream [[monix.reactive.Observer Observer]] given in
  *         `subscribe` will not receive concurrent events.
  *
  *         WARNING: if the buffer created by this operator is
  *         unbounded, it can blow up the process if the data source
  *         is pushing events faster than what the observer can
  *         consume, as it introduces an asynchronous boundary that
  *         eliminates the back-pressure requirements of the data
  *         source. Unbounded is the default
  *         [[monix.reactive.OverflowStrategy overflowStrategy]], see
  *         [[monix.reactive.OverflowStrategy OverflowStrategy]] for
  *         options.
  * @define onOverflowParam a function that is used for signaling a special
  *         event used to inform the consumers that an overflow event
  *         happened, function that receives the number of dropped
  *         events as a parameter (see [[OverflowStrategy.Evicted]])
  *
  * @define bufferWithSelectorDesc Periodically gather items emitted by
  *         an observable into bundles and emit these bundles rather than
  *         emitting the items one at a time, whenever the `selector`
  *         observable signals an event.
  *
  *         The resulting observable collects the elements of the source
  *         in a buffer and emits that buffer whenever the given `selector`
  *         observable emits an `onNext` event, when the buffer is emitted
  *         as a sequence downstream and then reset. Thus the resulting
  *         observable emits connected, non-overlapping bundles triggered
  *         by the given `selector`.
  *
  *         If `selector` terminates with an `onComplete`, then the resulting
  *         observable also terminates normally. If `selector` terminates with
  *         an `onError`, then the resulting observable also terminates with an
  *         error.
  *
  *         If the source observable completes, then the current buffer gets
  *         signaled downstream. If the source triggers an error then the
  *         current buffer is being dropped and the error gets propagated
  *         immediately.
  */
trait ObservableLike[+A, Self[+T] <: ObservableLike[T, Self]]
  extends Serializable { self: Self[A] =>

  /** Transforms the source using the given operator function. */
  def liftByOperator[B](operator: Operator[A,B]): Self[B]

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

  /** Concatenates the source with another observable.
    *
    * Ordering of subscription is preserved, so the second observable
    * starts only after the source observable is completed
    * successfully with an `onComplete`. On the other hand, the second
    * observable is never subscribed if the source completes with an
    * error.
    */
  def ++[B >: A](other: Observable[B]): Self[B] =
    self.transform(self => Observable.concat(self, other))

  /** Creates a new Observable that emits the given element and then it
    * also emits the events of the source (prepend operation).
    */
  def +:[B >: A](elem: B): Self[B] =
    self.transform(self => Observable.cons(elem, self))

  /** Creates a new Observable that emits the events of the source and
    * then it also emits the given element (appended to the stream).
    */
  def :+[B >: A](elem: B): Self[B] =
    self.transform(self => self ++ Observable.now(elem))

  /** Given the source observable and another `Observable`, emits all of
    * the items from the first of these Observables to emit an item
    * and cancel the other.
    */
  def ambWith[B >: A](other: Observable[B]): Self[B] =
    self.transform(self => Observable.firstStartedOf(self, other))

  /** $asyncBoundaryDescription
    *
    * @param overflowStrategy - $overflowStrategyParam
    */
  def asyncBoundary[B >: A](overflowStrategy: OverflowStrategy[B]): Self[B] =
    self.liftByOperator(new AsyncBoundaryOperator[B](overflowStrategy))

  /** Periodically gather items emitted by an observable into bundles
    * and emit these bundles rather than emitting the items one at a
    * time. This version of `buffer` is emitting items once the
    * internal buffer has reached the given count.
    *
    * If the source observable completes, then the current buffer gets
    * signaled downstream. If the source triggers an error then the
    * current buffer is being dropped and the error gets propagated
    * immediately.
    *
    * @param count the maximum size of each buffer before it should
    *        be emitted
    */
  def bufferTumbling(count: Int): Self[Seq[A]] =
    bufferSliding(count, count)

  /** Returns an observable that emits buffers of items it collects from
    * the source observable. The resulting observable emits buffers
    * every `skip` items, each containing `count` items.
    *
    * If the source observable completes, then the current buffer gets
    * signaled downstream. If the source triggers an error then the
    * current buffer is being dropped and the error gets propagated
    * immediately.
    *
    * For `count` and `skip` there are 3 possibilities:
    *
    * 1. in case `skip == count`, then there are no items dropped and
    *    no overlap, the call being equivalent to `buffer(count)`
    *
    * 2. in case `skip < count`, then overlap between buffers
    *    happens, with the number of elements being repeated being
    *    `count - skip`
    *
    * 3. in case `skip > count`, then `skip - count` elements start
    *    getting dropped between windows
    *
    * @param count the maximum size of each buffer before it should
    *        be emitted
    * @param skip how many items emitted by the source observable should
    *        be skipped before starting a new buffer. Note that when
    *        skip and count are equal, this is the same operation as
    *        `buffer(count)`
    */
  def bufferSliding(count: Int, skip: Int): Self[Seq[A]] =
    self.liftByOperator(new BufferSlidingOperator(count, skip))

  /** Periodically gather items emitted by an observable into bundles
    * and emit these bundles rather than emitting the items one at a
    * time.
    *
    * This version of `buffer` emits a new bundle of items
    * periodically, every timespan amount of time, containing all
    * items emitted by the source Observable since the previous bundle
    * emission.
    *
    * If the source observable completes, then the current buffer gets
    * signaled downstream. If the source triggers an error then the
    * current buffer is being dropped and the error gets propagated
    * immediately.
    *
    * @param timespan the interval of time at which it should emit
    *        the buffered bundle
    */
  def bufferTimed(timespan: FiniteDuration): Self[Seq[A]] =
    bufferTimedAndCounted(timespan, 0)

  /** Periodically gather items emitted by an observable into bundles
    * and emit these bundles rather than emitting the items one at a
    * time.
    *
    * The resulting observable emits connected, non-overlapping
    * buffers, each of a fixed duration specified by the `timespan`
    * argument or a maximum size specified by the `maxCount` argument
    * (whichever is reached first).
    *
    * If the source observable completes, then the current buffer gets
    * signaled downstream. If the source triggers an error then the
    * current buffer is being dropped and the error gets propagated
    * immediately.
    *
    * @param timespan the interval of time at which it should emit
    *        the buffered bundle
    * @param maxCount is the maximum bundle size, after which the
    *        buffered bundle gets forcefully emitted
    */
  def bufferTimedAndCounted(timespan: FiniteDuration, maxCount: Int): Self[Seq[A]] =
    transform(self => new BufferTimedObservable[A](self, timespan, maxCount))

  /** Periodically gather items emitted by an observable into bundles
    * and emit these bundles rather than emitting the items one at a
    * time. Back-pressure the source when the buffer is full.
    *
    * The resulting observable emits connected, non-overlapping
    * buffers, each of a fixed duration specified by the `period`
    * argument.
    *
    * The bundles are emitted at a fixed rate. If the source is
    * silent, then the resulting observable will start emitting empty
    * sequences.
    *
    * If the source observable completes, then the current buffer gets
    * signaled downstream. If the source triggers an error then the
    * current buffer is being dropped and the error gets propagated
    * immediately.
    *
    * A `maxSize` argument is specified as the capacity of the
    * bundle. In case the source is too fast and `maxSize` is reached,
    * then the source will be back-pressured.
    *
    * The difference with [[bufferTimedAndCounted]] is that
    * [[bufferTimedWithPressure]] applies back-pressure from the time
    * when the buffer is full until the buffer is emitted, whereas
    * [[bufferTimedAndCounted]] will forcefully emit the buffer when
    * it's full.
    *
    * @param period the interval of time at which it should emit
    *        the buffered bundle
    * @param maxSize is the maximum buffer size, after which the
    *        source starts being back-pressured
    */
  def bufferTimedWithPressure(period: FiniteDuration, maxSize: Int): Self[Seq[A]] =
    self.transform { source =>
      val sampler = Observable.intervalAtFixedRate(period, period)
      new BufferWithSelectorObservable(source, sampler, maxSize)
    }

  /** $bufferWithSelectorDesc
    *
    * @param selector is the observable that triggers the
    *        signaling of the current buffer
    */

  def bufferWithSelector[S](selector: Observable[S]): Self[Seq[A]] =
    self.transform(source => new BufferWithSelectorObservable[A,S](source, selector, 0))

  /** $bufferWithSelectorDesc
    *
    * A `maxSize` argument is specified as the capacity of the
    * bundle. In case the source is too fast and `maxSize` is reached,
    * then the source will be back-pressured.
    *
    * @param selector is the observable that triggers the signaling of the
    *        current buffer
    * @param maxSize is the maximum bundle size, after which the
    *        source starts being back-pressured
    */
  def bufferWithSelector[S](selector: Observable[S], maxSize: Int): Self[Seq[A]] =
    self.transform(source => new BufferWithSelectorObservable[A,S](source, selector, maxSize))

  /** Buffers signals while busy, after which it emits the
    * buffered events as a single bundle.
    *
    * This operator starts applying back-pressure when the
    * underlying buffer's size is exceeded.
    */
  def bufferIntrospective(maxSize: Int): Self[List[A]] =
    self.transform(self => new BufferIntrospectiveObservable[A](self, maxSize))

  /** Applies the given partial function to the source
    * for each element for which the given partial function is defined.
    *
    * @param pf the function that filters and maps the source
    * @return an observable that emits the transformed items by the
    *         given partial function
    */
  def collect[B](pf: PartialFunction[A, B]): Self[B] =
    self.liftByOperator(new CollectOperator(pf))

  /** Creates a new observable from the source and another given
    * observable, by emitting elements combined in pairs. If one of
    * the observables emits fewer events than the other, then the rest
    * of the unpaired events are ignored.
    *
    * See [[zip]] for an alternative that pairs the items in strict sequence.
    *
    * @param other is an observable that gets paired with the source
    */
  def combineLatest[B](other: Observable[B]): Self[(A,B)] =
    self.transform(self => new CombineLatest2Observable[A,B,(A,B)](self, other)((a,b) => (a,b)))

  /** Creates a new observable from the source and another given
    * observable, by emitting elements combined in pairs. If one of
    * the observables emits fewer events than the other, then the rest
    * of the unpaired events are ignored.
    *
    * See [[zipMap]] for an alternative that pairs the items
    * in strict sequence.
    *
    * @param other is an observable that gets paired with the source
    * @param f is a mapping function over the generated pairs
    */
  def combineLatestMap[B,R](other: Observable[B])(f: (A,B) => R): Self[R] =
    self.transform(self => new CombineLatest2Observable[A,B,R](self, other)(f))

  /** Ignores all items emitted by the source Observable and only calls
    * onCompleted or onError.
    *
    * @return an empty Observable that only calls onCompleted or onError,
    *         based on which one is called by the source Observable
    */
  def completed: Self[Nothing] =
    self.liftByOperator(CompletedOperator)

  /** $concatDescription
    *
    * @return $concatReturn
    */
  def concat[B](implicit ev: A <:< Observable[B]): Self[B] =
    concatMap[B](x => x)

  /** Applies a function that you supply to each item emitted by the
    * source observable, where that function returns observables,
    * and then concatenating those resulting sequences and
    * emitting the results of this concatenation.
    *
    * $concatMergeDifference
    */
  def concatMap[B](f: A => Observable[B]): Self[B] =
    self.transform(self => new ConcatMapObservable[A,B](self, f, delayErrors = false))

  /** $concatDescription
    *
    * $delayErrorsDescription
    *
    * @return $concatReturn
    */
  def concatDelayError[B](implicit ev: A <:< Observable[B]): Self[B] =
    concatMapDelayError(x => x)

  /** Applies a function that you supply to each item emitted by the
    * source observable, where that function returns sequences
    * and then concatenating those resulting sequences and emitting the
    * results of this concatenation.
    *
    * $delayErrorsDescription
    *
    * @param f a function that, when applied to an item emitted by
    *        the source, returns an observable
    * @return $concatReturn
    */
  def concatMapDelayError[B](f: A => Observable[B]): Self[B] =
    self.transform(self => new ConcatMapObservable[A,B](self, f, delayErrors = true))

  /** Creates a new Observable that emits the total number of `onNext`
    * events that were emitted by the source.
    *
    * Note that this Observable emits only one item after the source
    * is complete.  And in case the source emits an error, then only
    * that error will be emitted.
    */
  def countF: Self[Long] =
    self.liftByOperator(CountOperator)

  /** Only emit an item from an observable if a particular timespan has
    * passed without it emitting another item.
    *
    * Note: If the source observable keeps emitting items more
    * frequently than the length of the time window, then no items will
    * be emitted by the resulting observable.
    *
    * @param timeout the length of the window of time that must pass after
    *        the emission of an item from the source observable in
    *        which that observable emits no items in order for the
    *        item to be emitted by the resulting observable
    * @see [[echoOnce]] for a similar operator that also mirrors
    *     the source observable
    */
  def debounce(timeout: FiniteDuration): Self[A] =
    self.transform(self => new DebounceObservable(self, timeout, repeat = false))

  /** Doesn't emit anything until a `timeout` period passes without the
    * source emitting anything. When that timeout happens, we
    * subscribe to the observable generated by the given function, an
    * observable that will keep emitting until the source will break
    * the silence by emitting another event.
    *
    * Note: If the source observable keeps emitting items more
    * frequently than the length of the time window, then no items
    * will be emitted by the resulting Observable.
    *
    * @param f is a function that receives the last element generated
    *        by the source, generating an observable to be subscribed
    *        when the source is timing out
    * @param timeout the length of the window of time that must pass after
    *        the emission of an item from the source Observable in
    *        which that Observable emits no items in order for the
    *        item to be emitted by the resulting Observable
    */
  def debounceTo[B](timeout: FiniteDuration, f: A => Observable[B]): Self[B] =
    self.switchMap(a => f(a).delaySubscription(timeout))

  /** Emits the last item from the source Observable if a particular
    * timespan has passed without it emitting another item, and keeps
    * emitting that item at regular intervals until the source breaks
    * the silence.
    *
    * So compared to regular [[debounceTo]] this version
    * keeps emitting the last item of the source.
    *
    * Note: If the source Observable keeps emitting items more
    * frequently than the length of the time window then no items will
    * be emitted by the resulting Observable.
    *
    * @param period the length of the window of time that must pass after
    *        the emission of an item from the source Observable in
    *        which that Observable emits no items in order for the
    *        item to be emitted by the resulting Observable at regular
    *        intervals, also determined by period
    * @see [[echoRepeated]] for a similar operator that also mirrors
    *     the source observable
    */
  def debounceRepeated(period: FiniteDuration): Self[A] =
    self.transform(self => new DebounceObservable(self, period, repeat = true))

  /** Emit items from the source, or emit a default item if
    * the source completes after emitting no items.
    */
  def defaultIfEmpty[B >: A](default: => B): Self[B] =
    self.liftByOperator(new DefaultIfEmptyOperator[B](default _))

  /** Delays emitting the final `onComplete` event by the specified amount. */
  def delayOnComplete(delay: FiniteDuration): Self[A] =
    self.transform(self => new DelayOnCompleteObservable(self, delay))

  /** Returns an Observable that emits the items emitted by the source
    * Observable shifted forward in time by a specified delay.
    *
    * Each time the source Observable emits an item, delay starts a
    * timer, and when that timer reaches the given duration, the
    * Observable returned from delay emits the same item.
    *
    * NOTE: this delay refers strictly to the time between the
    * `onNext` event coming from our source and the time it takes the
    * downstream observer to get this event. On the other hand the
    * operator is also applying back-pressure, so on slow observers
    * the actual time passing between two successive events may be
    * higher than the specified `duration`.
    *
    * @param duration - the delay to shift the source by
    * @return the source Observable shifted in time by the specified delay
    */
  def delayOnNext(duration: FiniteDuration): Self[A] =
    self.transform(self => new DelayByTimespanObservable[A](self, duration))

  /** Returns an Observable that emits the items emitted by the source
    * Observable shifted forward in time.
    *
    * This variant of `delay` sets its delay duration on a per-item
    * basis by passing each item from the source Observable into a
    * function that returns an Observable and then monitoring those
    * Observables. When any such Observable emits an item or
    * completes, the Observable returned by delay emits the associated
    * item.
    *
    * @param selector is a function that returns an Observable for
    *        each item emitted by the source Observable, which is then
    *        used to delay the emission of that item by the resulting
    *        Observable until the Observable returned from `selector`
    *        emits an item
    * @return the source Observable shifted in time by
    *         the specified delay
    */
  def delayOnNextBySelector[B](selector: A => Observable[B]): Self[A] =
    self.transform(self => new DelayBySelectorObservable[A,B](self, selector))

  /** Hold an Observer's subscription request for a specified amount of
    * time before passing it on to the source Observable.
    *
    * @param timespan is the time to wait before the subscription
    *        is being initiated.
    */
  def delaySubscription(timespan: FiniteDuration): Self[A] =
    self.transform(self => new DelaySubscriptionByTimespanObservable(self, timespan))

  /** Hold an Observer's subscription request until the given `trigger`
    * observable either emits an item or completes, before passing it
    * on to the source Observable.
    *
    * If the given `trigger` completes in error, then the subscription is
    * terminated with `onError`.
    *
    * @param trigger the observable that must either emit an item or
    *        complete in order for the source to be subscribed.
    */
  def delaySubscriptionWith(trigger: Observable[Any]): Self[A] =
    self.transform(self => new DelaySubscriptionWithTriggerObservable(self, trigger))

  /** Converts the source Observable that emits `Notification[A]` (the
    * result of [[materialize]]) back to an Observable that emits `A`.
    */
  def dematerialize[B](implicit ev: A <:< Notification[B]): Self[B] =
    self.asInstanceOf[Self[Notification[B]]].liftByOperator(new DematerializeOperator[B])

  /** Suppress the duplicate elements emitted by the source Observable.
    *
    * WARNING: this requires unbounded buffering.
    */
  def distinct: Self[A] =
    self.liftByOperator(new DistinctOperator[A])

  /** Given a function that returns a key for each element emitted by
    * the source Observable, suppress duplicates items.
    *
    * WARNING: this requires unbounded buffering.
    */
  def distinctByKey[K](key: A => K): Self[A] =
    self.liftByOperator(new DistinctByKeyOperator(key))

  /** Suppress duplicate consecutive items emitted by the source
    * Observable
    */
  def distinctUntilChanged: Self[A] =
    self.liftByOperator(new DistinctUntilChangedOperator[A])

  /** Suppress duplicate consecutive items emitted by the source
    * Observable
    */
  def distinctUntilChangedByKey[K](key: A => K): Self[A] =
    self.liftByOperator(new DistinctUntilChangedByKeyOperator(key))

  /** Executes the given callback when the streaming is stopped
    * due to a downstream [[monix.execution.Ack.Stop Stop]] signal
    * returned by [[monix.reactive.Observer.onNext onNext]].
    */
  def doOnDownstreamStop(cb: => Unit): Self[A] =
    self.liftByOperator(new DoOnDownstreamStopOperator[A](cb))

  /** Executes the given callback when the connection is
    * being [[monix.execution.Cancelable.cancel cancelled]].
    */
  def doOnSubscriptionCancel(cb: => Unit): Self[A] =
    self.transform(self => new DoOnSubscriptionCancelObservable[A](self, cb))

  /** Executes the given callback when the stream has ended with an
    * `onComplete` event, but before the complete event is emitted.
    *
    * @param cb the callback to execute when the subscription is canceled
    */
  def doOnComplete(cb: => Unit): Self[A] =
    self.liftByOperator(new DoOnCompleteOperator[A](cb))

  /** Executes the given callback when the stream is interrupted with an
    * error, before the `onError` event is emitted downstream.
    *
    * NOTE: should protect the code in this callback, because if it
    * throws an exception the `onError` event will prefer signaling
    * the original exception and otherwise the behavior is undefined.
    */
  def doOnError(cb: Throwable => Unit): Self[A] =
    self.liftByOperator(new DoOnErrorOperator[A](cb))

  /** Executes the given callback when the stream has ended either with
    * an `onComplete` or `onError` event, or when the streaming stops by
    * a downstream `Stop` being signaled.
    *
    * It is the equivalent of calling:
    *
    *   - [[doOnComplete]]
    *   - [[doOnError]]
    *   - [[doOnDownstreamStop]]
    */
  def doOnTerminate(cb: => Unit): Self[A] =
    self.liftByOperator(new DoOnTerminateOperator[A](cb _))

  /** Executes the given callback for each element generated by the
    * source Observable, useful for doing side-effects.
    *
    * @return a new Observable that executes the specified
    *         callback for each element
    */
  def doOnNext(cb: A => Unit): Self[A] =
    self.liftByOperator(new DoOnNextOperator[A](cb))

  /** Executes the given callback only for the first element generated
    * by the source Observable, useful for doing a piece of
    * computation only when the stream starts.
    *
    * @return a new Observable that executes the specified callback
    *         only for the first element
    */
  def doOnStart(cb: A => Unit): Self[A] =
    self.liftByOperator(new DoOnStartOperator[A](cb))

  /** Executes the given callback before the subscription happens. */
  def doOnSubscribe(cb: => Unit): Self[A] =
    self.transform(self => new DoOnSubscribeObservable[A](self, cb))

  /** Drops the first `n` elements (from the start).
    *
    * @param n the number of elements to drop
    * @return a new Observable that drops the first ''n'' elements
    *         emitted by the source
    */
  def drop(n: Int): Self[A] =
    self.liftByOperator(new DropFirstOperator(n))

  /** Creates a new observable that drops the events of the source, only
    * for the specified `timestamp` window.
    *
    * @param timespan the window of time during which the new observable
    *        must drop events emitted by the source
    */
  def dropByTimespan(timespan: FiniteDuration): Self[A] =
    self.transform(self => new DropByTimespanObservable(self, timespan))

  /** Drops the last `n` elements (from the end).
    *
    * @param n the number of elements to drop
    * @return a new Observable that drops the first ''n'' elements
    *         emitted by the source
    */
  def dropLast(n: Int): Self[A] =
    self.liftByOperator(new DropLastOperator[A](n))

  /** Discard items emitted by the source until a second
    * observable emits an item or completes.
    *
    * If the `trigger` observable completes in error, then the
    * resulting observable will also end in error when it notices
    * it (next time an element is emitted by the source).
    *
    * @param trigger the observable that has to emit an item before the
    *        source begin to be mirrored by the resulting observable
    */
  def dropUntil(trigger: Observable[Any]): Self[A] =
    self.transform(self => new DropUntilObservable(self, trigger))

  /** Drops the longest prefix of elements that satisfy the given
    * predicate and returns a new observable that emits the rest.
    */
  def dropWhile(p: A => Boolean): Self[A] =
    self.liftByOperator(new DropByPredicateOperator(p))

  /** Drops the longest prefix of elements that satisfy the given
    * function and returns a new observable that emits the rest. In
    * comparison with [[dropWhile]], this version accepts a function
    * that takes an additional parameter: the zero-based index of the
    * element.
    */
  def dropWhileWithIndex(p: (A, Int) => Boolean): Self[A] =
    self.liftByOperator(new DropByPredicateWithIndexOperator(p))

  /** Utility that can be used for debugging purposes.
    */
  def dump(prefix: String, out: PrintStream = System.out): Self[A] =
    self.transform(self => new DumpObservable[A](self, prefix, out))

  /** Mirror the source observable as long as the source keeps emitting
    * items, otherwise if `timeout` passes without the source emitting
    * anything new then the observable will emit the last item.
    *
    * This is the rough equivalent of:
    * {{{
    *   Observable.merge(source, source.debounce(period))
    * }}}
    *
    * Note: If the source Observable keeps emitting items more
    * frequently than the length of the time window then the resulting
    * observable will mirror the source exactly.
    *
    * @param timeout the window of silence that must pass in order for the
    *        observable to echo the last item
    */
  def echoOnce(timeout: FiniteDuration): Self[A] =
    self.transform(self => new EchoObservable(self, timeout, onlyOnce = true))

  /** Mirror the source observable as long as the source keeps emitting
    * items, otherwise if `timeout` passes without the source emitting
    * anything new then the observable will start emitting the last
    * item repeatedly.
    *
    * Note: If the source Observable keeps emitting items more
    * frequently than the length of the time window then the resulting
    * observable will mirror the source exactly.
    *
    * @param timeout the window of silence that must pass in order for the
    *        observable to start echoing the last item
    */
  def echoRepeated(timeout: FiniteDuration): Self[A] =
    self.transform(self => new EchoObservable(self, timeout, onlyOnce = false))


  /** Creates a new Observable that emits the events of the source and
    * then it also emits the given elements (appended to the stream).
    */
  def endWith[B >: A](elems: Seq[B]): Self[B] =
    self.transform(self => self ++ Observable.fromIterable(elems))

  /** Emits the given exception instead of `onComplete`.
    *
    * @param error the exception to emit onComplete
    * @return a new Observable that emits an exception onComplete
    */
  def endWithError(error: Throwable): Self[A] =
    self.liftByOperator(new EndWithErrorOperator[A](error))

  /** Returns an Observable which emits a single value, 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 Observable, returning `true` if they pass the
    *        filter
    * @return an Observable that emits only true or false in case
    *         the given predicate holds or not for at least one item
    */
  def existsF(p: A => Boolean): Self[Boolean] =
    findF(p).foldLeftF(false)((_, _) => true)

  /** Returns an observable that emits a single Throwable, in case an
    * error was thrown by the source, otherwise it isn't
    * going to emit anything.
    */
  def failed: Self[Throwable] =
    self.liftByOperator(FailedOperator)

  /** Only emits those items for which the given predicate holds.
    *
    * @param p a function that evaluates the items emitted by the source
    *        returning `true` if they pass the filter
    * @return a new observable that emits only those items in the source
    *         for which the filter evaluates as `true`
    */
  def filter(p: A => Boolean): Self[A] =
    self.liftByOperator(new FilterOperator(p))

  /** Returns an Observable which only 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 an Observable that emits only the first item in the original
    *         Observable for which the filter evaluates as `true`
    */
  def findF(p: A => Boolean): Self[A] =
    filter(p).headF

  /** Emits the first element emitted by the source, or otherwise if the
    * source is completed without emitting anything, then the
    * `default` is emitted.
    *
    * Alias for `headOrElse`.
    */
  def firstOrElseF[B >: A](default: => B): Self[B] =
    headOrElseF(default)

  /** Applies a function that you supply to each item emitted by the
    * source observable, where that function returns sequences that
    * [[Observable can be observed]], and then concatenating those
    * resulting sequences and emitting the results of this concatenation.
    *
    * Alias for [[concatMap]].
    *
    * $concatMergeDifference
    */
  def flatMap[B](f: A => Observable[B]): Self[B] =
    self.concatMap(f)

  /** Applies a function that you supply to each item emitted by the
    * source observable, where that function returns sequences
    * and then concatenating those resulting sequences and emitting the
    * results of this concatenation.
    *
    * It's an alias for [[concatMapDelayError]].
    *
    * @param f a function that, when applied to an item emitted by
    *        the source Observable, returns an Observable
    * @return an Observable that emits the result of applying the
    *         transformation function to each item emitted by the
    *         source Observable and concatenating the results of the
    *         Observables obtained from this transformation.
    */
  def flatMapDelayError[B](f: A => Observable[B]): Self[B] =
    concatMapDelayError(f)

  /** An alias of [[switchMap]].
    *
    * $switchMapDescription
    */
  def flatMapLatest[B](f: A => Observable[B]): Self[B] =
    self.switchMap(f)

  /** Applies a binary operator to a start value and to elements
    * produced by the source observable, going from left to right,
    * producing and concatenating observables along the way.
    *
    * It's the combination between [[scan]] and [[flatMap]].
    */
  def flatScan[R](initial: => R)(op: (R, A) => Observable[R]): Self[R] =
    self.transform(self => new FlatScanObservable[A,R](self, initial _, op, delayErrors = false))

  /** Applies a binary operator to a start value and to elements
    * produced by the source observable, going from left to right,
    * producing and concatenating observables along the way.
    *
    * This version of [[flatScan]] delays all errors until `onComplete`,
    * when it will finally emit a `CompositeException`.
    * It's the combination between [[scan]] and [[flatMapDelayError]].
    */
  def flatScanDelayError[R](initial: => R)(op: (R, A) => Observable[R]): Self[R] =
    self.transform(self => new FlatScanObservable[A,R](self, initial _, op, delayErrors = true))

  /** $concatDescription
    *
    * Alias for [[concat]].
    *
    * @return $concatReturn
    */
  def flatten[B](implicit ev: A <:< Observable[B]): Self[B] =
    concat

  /** Alias for [[concatDelayError]].
    *
    * $concatDescription
    * $delayErrorsDescription
    *
    * @return $concatReturn
    */
  def flattenDelayError[B](implicit ev: A <:< Observable[B]): Self[B] =
    concatDelayError

  /** Alias for [[switch]]
    *
    * $switchDescription
    */
  def flattenLatest[B](implicit ev: A <:< Observable[B]): Self[B] =
    self.switch

  /** Applies a binary operator to a start value and all elements of
    * this Observable, going left to right and returns a new
    * Observable that emits only one item before `onComplete`.
    *
    * @param initial is the initial state, specified as a possibly lazy value;
    *        it gets evaluated when the subscription happens and if it triggers
    *        an error then the subscriber will get immediately terminated
    *        with an error
    *
    * @param op is an operator that will fold the signals of the source
    *        observable, returning the next state
    */
  def foldLeftF[R](initial: => R)(op: (R, A) => R): Self[R] =
    self.transform(source => new FoldLeftObservable[A,R](source, initial _, op))

  /** 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 [[foldLeftF]] is equivalent to this function
    * being called with an operator always returning `true` as the first
    * member of its result.
    *
    * @param initial is the initial state, specified as a possibly lazy value;
    *        it gets evaluated when the subscription happens and if it
    *        triggers an error then the subscriber will get immediately
    *        terminated with an error
    *
    * @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 foldWhileF[R](initial: => R)(op: (R,A) => (Boolean, R)): Self[R] =
    self.transform(source => new FoldWhileObservable[A,R](source, initial _, op))

  /** Returns an Observable 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 an Observable that emits only true or false in case the given
    *         predicate holds or not for all the items
    */
  def forAllF(p: A => Boolean): Self[Boolean] =
    existsF(e => !p(e)).map(r => !r)

  /** Groups the items emitted by an Observable according to a specified
    * criterion, and emits these grouped items as GroupedObservables,
    * one GroupedObservable per group.
    *
    * Note: A [[monix.reactive.observables.GroupedObservable GroupedObservable]]
    * will cache the items it is to emit until such time as it is
    * subscribed to. For this reason, in order to avoid memory leaks,
    * you should not simply ignore those GroupedObservables that do
    * not concern you. Instead, you can signal to them that they may
    * discard their buffers by doing something like `source.take(0)`.
    *
    * @param keySelector  a function that extracts the key for each item
    */
  def groupBy[K](keySelector: A => K)
    (implicit keysBuffer: Synchronous[Nothing] = OverflowStrategy.Unbounded): Self[GroupedObservable[K, A]] =
    self.liftByOperator(new GroupByOperator[A,K](keysBuffer, keySelector))

  /** Only emits the first element emitted by the source observable,
    * after which it's completed immediately.
    */
  def headF: Self[A] = take(1)

  /** Emits the first element emitted by the source, or otherwise if the
    * source is completed without emitting anything, then the
    * `default` is emitted.
    */
  def headOrElseF[B >: A](default: => B): Self[B] =
    headF.foldLeftF(Option.empty[B])((_, elem) => Some(elem)).map {
      case Some(elem) => elem
      case None => default
    }

  /** Alias for [[completed]]. Ignores all items emitted by
    * the source and only calls onCompleted or onError.
    *
    * @return an empty sequence that only calls onCompleted or onError,
    *         based on which one is called by the source Observable
    */
  def ignoreElements: Self[Nothing] =
    self.liftByOperator(CompletedOperator)

  /** Returns an Observable that emits true if the source Observable is
    * empty, otherwise false.
    */
  def isEmptyF: Self[Boolean] =
    self.liftByOperator(IsEmptyOperator)

  /** 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.
    *
    * @param other is an observable that interleaves with the source
    * @return a new observable sequence that alternates emission of
    *         the items from both child streams
    */
  def interleave[B >: A](other: Observable[B]): Self[B] =
    self.transform(self ⇒ new Interleave2Observable(self, other))

  /** Only emits the last element emitted by the source observable,
    * after which it's completed immediately.
    */
  def lastF: Self[A] = takeLast(1)

  /** Returns a new observable that applies the given function
    * to each item emitted by the source and emits the result.
    */
  def map[B](f: A => B): Self[B] =
    self.liftByOperator(new MapOperator(f))

  /** Converts the source Observable that emits `A` into an Observable
    * that emits `Notification[A]`.
    */
  def materialize: Self[Notification[A]] =
    self.liftByOperator(new MaterializeOperator[A])

  /** Takes the elements of the source Observable and emits the maximum
    * value, after the source has completed.
    */
  def maxF[B >: A](implicit ev: Ordering[B]): Self[B] =
    self.liftByOperator(new MaxOperator[B])

  /** Takes the elements of the source Observable and emits the element
    * that has the maximum key value, where the key is generated by
    * the given function `f`.
    */
  def maxByF[B](f: A => B)(implicit ev: Ordering[B]): Self[A] =
    self.liftByOperator(new MaxByOperator[A,B](f))

  /** $mergeDescription
    *
    * @note $defaultOverflowStrategy
    * @return $mergeReturn
    */
  def merge[B](implicit ev: A <:< Observable[B],
    os: OverflowStrategy[B] = OverflowStrategy.Default): Self[B] =
    self.mergeMap(x => x)(os)

  /** $mergeDescription
    *
    * $delayErrorsDescription
    *
    * @note $defaultOverflowStrategy
    * @return $mergeReturn
    */
  def mergeDelayErrors[B](implicit ev: A <:< Observable[B],
    os: OverflowStrategy[B] = OverflowStrategy.Default): Self[B] =
    self.mergeMap(x => x)(os)

  /** $mergeMapDescription
    *
    * @param f - the transformation function
    * @return $mergeMapReturn
    */
  def mergeMap[B](f: A => Observable[B])
    (implicit os: OverflowStrategy[B] = OverflowStrategy.Default): Self[B] =
    self.transform(self => new MergeMapObservable[A,B](self, f, os, delayErrors = false))

  /** $mergeMapDescription
    *
    * $delayErrorsDescription
    *
    * @param f - the transformation function
    * @return $mergeMapReturn
    */
  def mergeMapDelayErrors[B](f: A => Observable[B])
    (implicit os: OverflowStrategy[B] = OverflowStrategy.Default): Self[B] =
    self.transform(self => new MergeMapObservable[A,B](self, f, os, delayErrors = true))

  /** Takes the elements of the source Observable and emits the minimum
    * value, after the source has completed.
    */
  def minF[B >: A](implicit ev: Ordering[B]): Self[B] =
    self.liftByOperator(new MinOperator[B]()(ev))

  /** Takes the elements of the source Observable and emits the element
    * that has the minimum key value, where the key is generated by
    * the given function `f`.
    */
  def minByF[B](f: A => B)(implicit ev: Ordering[B]): Self[A] =
    self.liftByOperator(new MinByOperator[A,B](f))

  /** Returns an Observable that emits false if the source Observable is
    * empty, otherwise true.
    */
  def nonEmptyF: Self[Boolean] =
    self.liftByOperator(IsEmptyOperator).map(b => !b)

  /** Specify an override for the [[monix.execution.Scheduler Scheduler]]
    * that will be used for subscribing and for observing the source.
    *
    * Normally the [[monix.execution.Scheduler Scheduler]] gets injected
    * implicitly when doing `subscribe`, but this operator overrides
    * the injected subscriber for the given source. And if the source is
    * normally using that injected scheduler (given by `subscribe`),
    * then the effect will be that all processing will now happen
    * on the override.
    *
    * To put it in other words, in Monix it's usually the consumer and
    * not the producer that specifies the scheduler and this operator
    * allows for a different behavior.
    *
    * This operator also includes the effects of [[subscribeOn]],
    * meaning that the subscription logic itself will start on
    * the provided scheduler.
    *
    * IMPORTANT: This operator is a replacement for the
    * [[http://reactivex.io/documentation/operators/observeon.html observeOn operator]]
    * from ReactiveX, but does not work in the same way. The `observeOn`
    * operator forces the signaling to happen on a given `Scheduler`, but
    * `executeOn` is more relaxed, usage is not forced, the source just
    * gets injected with a different scheduler and it's up to the source
    * to actually use it. This also means the effects are more far reaching,
    * because the whole chain until the call of this operator is affected.
    */
  def executeOn(scheduler: Scheduler): Self[A] =
    self.transform(source => new ExecuteOnObservable[A](source, scheduler))

  /** If the connection is [[monix.execution.Cancelable.cancel cancelled]]
    * then trigger a `CancellationException`.
    *
    * A connection can be cancelled with the help of the
    * [[monix.execution.Cancelable Cancelable]]
    * returned on [[Observable.subscribe(subscriber* subscribe]].
    *
    * Because the cancellation is effectively concurrent with the
    * signals the [[monix.reactive.Observer Observer]] receives and because
    * we need to uphold the contract, this operator will effectively
    * synchronize access to [[monix.reactive.Observer.onNext onNext]],
    * [[monix.reactive.Observer.onComplete onComplete]] and
    * [[monix.reactive.Observer.onError onError]]. It will also watch
    * out for asynchronous [[monix.execution.Ack.Stop Stop]] events.
    *
    * In other words, this operator does heavy synchronization, can
    * prove to be inefficient and you should avoid using it because
    * the signaled error can interfere with functionality from other
    * operators that use cancelation internally and cancellation in
    * general is a side-effecting operation that should be avoided,
    * unless it's necessary.
    */
  def onCancelTriggerError: Self[A] =
    self.transform(self => new OnCancelTriggerErrorObservable[A](self))

  /** Returns an Observable that mirrors the behavior of the source,
    * unless the source is terminated with an `onError`, in which case
    * the streaming of events continues with the specified backup
    * sequence.
    *
    * The created Observable mirrors the behavior of the source in
    * case the source does not end with an error.
    *
    * NOTE that compared with `onErrorResumeNext` from Rx.NET, the
    * streaming is not resumed in case the source is terminated
    * normally with an `onComplete`.
    *
    * @param that is a backup sequence that's being subscribed
    *        in case the source terminates with an error.
    */
  def onErrorFallbackTo[B >: A](that: Observable[B]): Self[B] =
    self.onErrorHandleWith(_ => that)

  /** Returns an observable that mirrors the behavior of the source,
    * unless the source is terminated with an `onError`, in which
    * case the streaming of events fallbacks to an observable
    * emitting a single element generated by the backup function.
    *
    * See [[onErrorRecover]] for the version that takes a
    * partial function as a parameter.
    *
    * @param f - a function that matches errors with a
    *        backup element that is emitted when the source
    *        throws an error.
    */
  def onErrorHandle[B >: A](f: Throwable => B): Self[B] =
    onErrorHandleWith { elem => Observable.now(f(elem)) }

  /** Returns an Observable that mirrors the behavior of the source,
    * unless the source is terminated with an `onError`, in which case
    * the streaming of events continues with the specified backup
    * sequence generated by the given function.
    *
    * See [[onErrorRecoverWith]] for the version that takes a
    * partial function as a parameter.
    *
    * @param f is a function that matches errors with a
    *        backup throwable that is subscribed when the source
    *        throws an error.
    */
  def onErrorHandleWith[B >: A](f: Throwable => Observable[B]): Self[B] =
    self.transform(self => new OnErrorRecoverWithObservable(self, f))

  /** Returns an observable that mirrors the behavior of the source,
    * unless the source is terminated with an `onError`, in which
    * case the streaming of events fallbacks to an observable
    * emitting a single element generated by the backup function.
    *
    * The created Observable mirrors the behavior of the source
    * in case the source does not end with an error or if the
    * thrown `Throwable` is not matched.
    *
    * See [[onErrorHandle]] for the version that takes a
    * total function as a parameter.
    *
    * @param pf - a function that matches errors with a
    *        backup element that is emitted when the source
    *        throws an error.
    */
  def onErrorRecover[B >: A](pf: PartialFunction[Throwable, B]): Self[B] =
    onErrorHandleWith(ex => (pf andThen Observable.now).applyOrElse(ex, Observable.raiseError))

  /** Returns an Observable that mirrors the behavior of the source,
    * unless the source is terminated with an `onError`, in which case
    * the streaming of events continues with the specified backup
    * sequence generated by the given function.
    *
    * The created Observable mirrors the behavior of the source in
    * case the source does not end with an error or if the thrown
    * `Throwable` is not matched.
    *
    * See [[onErrorHandleWith]] for the version that takes a
    * total function as a parameter.
    *
    * @param pf is a function that matches errors with a
    *        backup throwable that is subscribed when the source
    *        throws an error.
    */
  def onErrorRecoverWith[B >: A](pf: PartialFunction[Throwable, Observable[B]]): Self[B] =
    onErrorHandleWith(ex => pf.applyOrElse(ex, Observable.raiseError))

  /** Returns an Observable that mirrors the behavior of the source,
    * unless the source is terminated with an `onError`, in which case
    * it tries subscribing to the source again in the hope that it
    * will complete without an error.
    *
    * The number of retries is limited by the specified `maxRetries`
    * parameter, so for an Observable that always ends in error the
    * total number of subscriptions that will eventually happen is
    * `maxRetries + 1`.
    */
  def onErrorRestart(maxRetries: Long): Self[A] = {
    require(maxRetries >= 0, "maxRetries should be positive")
    self.transform(self => new OnErrorRetryCountedObservable(self, maxRetries))
  }

  /** Returns an Observable that mirrors the behavior of the source,
    * unless the source is terminated with an `onError`, in which case
    * it tries subscribing to the source again in the hope that it
    * will complete without an error.
    *
    * The given predicate establishes if the subscription should be
    * retried or not.
    */
  def onErrorRestartIf(p: Throwable => Boolean): Self[A] =
    self.transform(self => new OnErrorRetryIfObservable[A](self, p))

  /** Returns an Observable that mirrors the behavior of the source,
    * unless the source is terminated with an `onError`, in which case
    * it tries subscribing to the source again in the hope that it
    * will complete without an error.
    *
    * NOTE: The number of retries is unlimited, so something like
    * `Observable.error(new RuntimeException).onErrorRestartUnlimited`
    * will loop forever.
    */
  def onErrorRestartUnlimited: Self[A] =
    self.transform(self => new OnErrorRetryCountedObservable(self, -1))

  /** Given a [[monix.reactive.Pipe Pipe]], transform
    * the source observable with it.
    */
  def pipeThrough[I >: A, B](pipe: Pipe[I,B]): Self[B] =
    self.liftByOperator(new PipeThroughOperator(pipe))

  /** Applies a binary operator to a start value and all elements of
    * this Observable, going left to right and returns a new
    * Observable that emits only one item before `onComplete`.
    */
  def reduce[B >: A](op: (B, B) => B): Self[B] =
    self.liftByOperator(new ReduceOperator[B](op))

  /** Repeats the items emitted by the source continuously. It
    * caches the generated items until `onComplete` and repeats them
    * forever.
    *
    * It terminates either on error or if the source is empty.
    */
  def repeat: Self[A] =
    self.transform(self => new RepeatObservable[A](self))

  /** Keeps restarting / resubscribing the source until the predicate
    * returns `true` for the the first emitted element, after which
    * it starts mirroring the source.
    */
  def restartUntil(p: A => Boolean): Self[A] =
    self.transform(self => new RestartUntilObservable[A](self, p))

  /** Emit the most recent items emitted by the source within
    * periodic time intervals.
    *
    * Use the `sample` operator to periodically look at an observable
    * to see what item it has most recently emitted since the previous
    * sampling. Note that if the source observable has emitted no
    * items since the last time it was sampled, the observable that
    * results from the `sample` operator will emit no item for that
    * sampling period.
    *
    * @see [[sampleBy]] for fine control
    * @see [[sampleRepeated]] for repeating the last value on silence
    * @param period the timespan at which sampling occurs
    */
  def sample(period: FiniteDuration): Self[A] =
    self.sampleBy(Observable.intervalAtFixedRate(period, period))

  /** Returns an observable that, when the specified sampler
    * emits an item or completes, emits the most recently emitted item
    * (if any) emitted by the source since the previous
    * emission from the sampler.
    *
    * Use the `sampleBy` operator to periodically look at an observable
    * to see what item it has most recently emitted since the previous
    * sampling. Note that if the source observable has emitted no
    * items since the last time it was sampled, the observable that
    * results from the `sampleBy` operator will emit no item.
    *
    * @see [[sample]] for periodic sampling
    * @see [[sampleRepeatedBy]] for repeating the last value on silence
    * @param sampler - the observable to use for sampling the source
    */
  def sampleBy[B](sampler: Observable[B]): Self[A] =
    self.transform(self => new ThrottleLastObservable[A,B](self, sampler, shouldRepeatOnSilence = false))

  /** Emit the most recent items emitted by an observable within
    * periodic time intervals. If no new value has been emitted since
    * the last time it was sampled, it signals the last emitted value
    * anyway.
    *
    * @see [[sample]] for a variant that doesn't repeat the last value on silence
    * @see [[sampleRepeatedBy]] for fine control
    * @param period the timespan at which sampling occurs
    */
  def sampleRepeated(period: FiniteDuration): Self[A] =
    self.sampleRepeatedBy(Observable.intervalAtFixedRate(period, period))

  /** Returns an observable that, when the specified sampler observable
    * emits an item or completes, emits the most recently emitted item
    * (if any) emitted by the source Observable since the previous
    * emission from the sampler observable. If no new value has been
    * emitted since the last time it was sampled, it signals the last
    * emitted value anyway.
    *
    * @see [[sampleBy]] for a variant that doesn't repeat the last value on silence
    * @see [[sampleRepeated]] for a periodic sampling
    * @param sampler - the Observable to use for sampling the source Observable
    */
  def sampleRepeatedBy[B](sampler: Observable[B]): Self[A] =
    self.transform(self => new ThrottleLastObservable[A,B](self, sampler, shouldRepeatOnSilence = true))

  /** Applies a binary operator to a start value and all elements of
    * this Observable, going left to right and returns a new
    * Observable that emits on each step the result of the applied
    * function.
    *
    * Similar to [[foldLeftF]], but emits the state on each
    * step. Useful for modeling finite state machines.
    */
  def scan[R](initial: => R)(f: (R, A) => R): Self[R] =
    self.transform(source => new ScanObservable[A,R](source, initial _, f))

  /** Creates a new Observable that emits the given elements and then it
    * also emits the events of the source (prepend operation).
    */
  def startWith[B >: A](elems: Seq[B]): Self[B] =
    self.transform(self => Observable.fromIterable(elems) ++ self)

  /** Returns a new Observable that uses the specified `Scheduler` for
    * initiating the subscription.
    */
  def subscribeOn(scheduler: Scheduler): Self[A] =
    self.transform(self => new SubscribeOnObservable[A](self, scheduler))

  /** Given a source that emits numeric values, the `sum` operator sums
    * up all values and at onComplete it emits the total.
    */
  def sumF[B >: A : Numeric]: Self[B] =
    self.liftByOperator(new SumOperator[B])

  /** $switchDescription */
  def switch[B](implicit ev: A <:< Observable[B]): Self[B] =
    self.switchMap(x => x)

  /** $switchMapDescription */
  def switchMap[B](f: A => Observable[B]): Self[B] =
    self.transform(self => new SwitchMapObservable[A,B](self, f))

  /** In case the source is empty, switch to the given backup. */
  def switchIfEmpty[B >: A](backup: Observable[B]): Self[B] =
    self.transform(self => new SwitchIfEmptyObservable[B](self, backup))

  /** Drops the first element of the source observable,
    * emitting the rest.
    */
  def tail: Self[A] = drop(1)

  /** Selects the first `n` elements (from the start).
    *
    * @param  n the number of elements to take
    * @return a new Observable that emits only the first
    *         `n` elements from the source
    */
  def take(n: Long): Self[A] =
    self.liftByOperator(new TakeLeftOperator(n))

  /** Creates a new Observable that emits the events of the source, only
    * for the specified `timestamp`, after which it completes.
    *
    * @param timespan the window of time during which the new Observable
    *        is allowed to emit the events of the source
    */
  def takeByTimespan(timespan: FiniteDuration): Self[A] =
    self.transform(self => new TakeLeftByTimespanObservable(self, timespan))

  /** Creates a new observable that only emits the last `n` elements
    * emitted by the source.
    *
    * In case the source triggers an error, then the underlying
    * buffer gets dropped and the error gets emitted immediately.
    */
  def takeLast(n: Int): Self[A] =
    self.liftByOperator(new TakeLastOperator(n))

  /** Creates a new observable that mirrors the source until
    * the given `trigger` emits either an element or `onComplete`,
    * after which it is completed.
    *
    * The resulting observable is completed as soon as `trigger`
    * emits either an `onNext` or `onComplete`. If `trigger`
    * emits an `onError`, then the resulting observable is also
    * completed with error.
    *
    * @param trigger is an observable that will cancel the
    *        streaming as soon as it emits an event
    */
  def takeUntil(trigger: Observable[Any]): Self[A] =
    self.transform(source => new TakeUntilObservable[A](source, trigger))

  /** Takes longest prefix of elements that satisfy the given predicate
    * and returns a new Observable that emits those elements.
    */
  def takeWhile(p: A => Boolean): Self[A] =
    self.liftByOperator(new TakeByPredicateOperator(p))

  /** Takes longest prefix of elements that satisfy the given predicate
    * and returns a new Observable that emits those elements.
    */
  def takeWhileNotCanceled(c: BooleanCancelable): Self[A] =
    self.liftByOperator(new TakeWhileNotCanceledOperator(c))

  /** Returns an Observable that emits only the first item emitted by
    * the source Observable during sequential time windows of a
    * specified duration.
    *
    * This differs from [[Observable!.throttleLast]] in that this only
    * tracks passage of time whereas `throttleLast` ticks at scheduled
    * intervals.
    *
    * @param interval time to wait before emitting another item after
    *        emitting the last item
    */
  def throttleFirst(interval: FiniteDuration): Self[A] =
    self.liftByOperator(new ThrottleFirstOperator[A](interval))

  /** Emit the most recent items emitted by the source within
    * periodic time intervals.
    *
    * Alias for [[sample]].
    *
    * @param period duration of windows within which the last item
    *        emitted by the source Observable will be emitted
    */
  def throttleLast(period: FiniteDuration): Self[A] =
    sample(period)

  /** Only emit an item from an observable if a particular timespan has
    * passed without it emitting another item.
    *
    * Note: If the source observable keeps emitting items more
    * frequently than the length of the time window, then no items will
    * be emitted by the resulting observable.
    *
    * Alias for [[debounce]].
    *
    * @param timeout the length of the window of time that must pass after
    *        the emission of an item from the source observable in
    *        which that observable emits no items in order for the
    *        item to be emitted by the resulting observable
    * @see [[echoOnce]] for a similar operator that also mirrors
    *     the source observable
    */
  def throttleWithTimeout(timeout: FiniteDuration): Self[A] =
    debounce(timeout)

  /** Returns an observable that mirrors the source but that will trigger a
    * [[monix.reactive.exceptions.DownstreamTimeoutException DownstreamTimeoutException]]
    * in case the downstream subscriber takes more than the given timespan
    * to process an `onNext` message.
    *
    * Note that this ignores the time it takes for the upstream to send
    * `onNext` messages. For detecting slow producers see [[timeoutOnSlowUpstream]].
    *
    * @param timeout maximum duration for `onNext`.
    */
  def timeoutOnSlowDownstream(timeout: FiniteDuration): Self[A] =
    self.transform(self => new DownstreamTimeoutObservable[A](self, timeout))

  /** Returns an observable that mirrors the source but applies a timeout
    * for each emitted item by the upstream. If the next item isn't
    * emitted within the specified timeout duration starting from its
    * predecessor, the resulting Observable terminates and notifies
    * observers of a TimeoutException.
    *
    * Note that this ignores the time it takes to process `onNext`.
    * If dealing with a slow consumer, see [[timeoutOnSlowDownstream]].
    *
    * @param timeout maximum duration between emitted items before
    *        a timeout occurs (ignoring the time it takes to process `onNext`)
    */
  def timeoutOnSlowUpstream(timeout: FiniteDuration): Self[A] =
    self.transform(self => new UpstreamTimeoutObservable[A](self, timeout))

  /** Returns an observable that mirrors the source but applies a timeout
    * for each emitted item by the upstream. If the next item isn't
    * emitted within the specified timeout duration starting from its
    * predecessor, the source is terminated and the downstream gets
    * subscribed to the given backup.
    *
    * Note that this ignores the time it takes to process `onNext`.
    * If dealing with a slow consumer, see [[timeoutOnSlowDownstream]].
    *
    * @param timeout maximum duration between emitted items before
    *        a timeout occurs (ignoring the time it takes to process `onNext`)
    * @param backup is the alternative data source to subscribe to on timeout
    */
  def timeoutOnSlowUpstreamTo[B >: A](timeout: FiniteDuration, backup: Observable[B]): Self[B] =
    self.timeoutOnSlowUpstream(timeout).onErrorHandleWith {
      case UpstreamTimeoutException(`timeout`) => backup
      case other => Observable.raiseError(other)
    }

  /** While the destination observer is busy, buffers events, applying
    * the given overflowStrategy.
    *
    * @param overflowStrategy - $overflowStrategyParam
    */
  def whileBusyBuffer[B >: A](overflowStrategy: OverflowStrategy.Synchronous[B]): Self[B] =
    asyncBoundary(overflowStrategy)

  /** While the destination observer is busy, drop the incoming events.
    */
  def whileBusyDropEvents: Self[A] =
    self.liftByOperator(new WhileBusyDropEventsOperator[A])

  /** While the destination observer is busy, drop the incoming events.
    * When the downstream recovers, we can signal a special event
    * meant to inform the downstream observer how many events where
    * dropped.
    *
    * @param onOverflow - $onOverflowParam
    */
  def whileBusyDropEventsAndSignal[B >: A](onOverflow: Long => B): Self[B] =
    self.liftByOperator(new WhileBusyDropEventsAndSignalOperator[B](onOverflow))

  /** Combines the elements emitted by the source with the latest element
    * emitted by another observable.
    *
    * Similar with `combineLatest`, but only emits items when the single source
    * emits an item (not when any of the Observables that are passed to the operator
    * do, as combineLatest does).
    *
    * @param other is an observable that gets paired with the source
    * @param f is a mapping function over the generated pairs
    */
  def withLatestFrom[B,R](other: Observable[B])(f: (A,B) => R): Self[R] =
    self.transform(source => new WithLatestFromObservable[A,B,R](source, other, f))

  /** Combines the elements emitted by the source with the latest elements
    * emitted by two observables.
    *
    * Similar with `combineLatest`, but only emits items when the single source
    * emits an item (not when any of the Observables that are passed to the operator
    * do, as combineLatest does).
    *
    * @param o1 is the first observable that gets paired with the source
    * @param o2 is the second observable that gets paired with the source
    * @param f is a mapping function over the generated pairs
    */
  def withLatestFrom2[B1,B2,R](o1: Observable[B1], o2: Observable[B2])(f: (A,B1,B2) => R): Self[R] =
    self.transform(source =>
      source.withLatestFrom(Observable.combineLatest2(o1,o2)) { (a, tuple) =>
        f(a, tuple._1, tuple._2)
      })

  /** Combines the elements emitted by the source with the latest elements
    * emitted by three observables.
    *
    * Similar with `combineLatest`, but only emits items when the single source
    * emits an item (not when any of the Observables that are passed to the operator
    * do, as combineLatest does).
    *
    * @param o1 is the first observable that gets paired with the source
    * @param o2 is the second observable that gets paired with the source
    * @param o3 is the third observable that gets paired with the source
    * @param f is a mapping function over the generated pairs
    */
  def withLatestFrom3[B1,B2,B3,R](o1: Observable[B1], o2: Observable[B2], o3: Observable[B3])
    (f: (A,B1,B2,B3) => R): Self[R] =
    self.transform(source =>
      source.withLatestFrom(Observable.combineLatest3(o1,o2,o3)) { (a, o) =>
        f(a,o._1,o._2,o._3)
      })

  /** Combines the elements emitted by the source with the latest elements
    * emitted by four observables.
    *
    * Similar with `combineLatest`, but only emits items when the single source
    * emits an item (not when any of the Observables that are passed to the operator
    * do, as combineLatest does).
    *
    * @param o1 is the first observable that gets paired with the source
    * @param o2 is the second observable that gets paired with the source
    * @param o3 is the third observable that gets paired with the source
    * @param o4 is the fourth observable that gets paired with the source
    * @param f is a mapping function over the generated pairs
    */
  def withLatestFrom4[B1,B2,B3,B4,R](
    o1: Observable[B1], o2: Observable[B2], o3: Observable[B3], o4: Observable[B4])
    (f: (A,B1,B2,B3,B4) => R): Self[R] =
    self.transform(source =>
      source.withLatestFrom(Observable.combineLatest4(o1,o2,o3,o4)) { (a, o) =>
        f(a,o._1,o._2,o._3,o._4)
      })

  /** Combines the elements emitted by the source with the latest elements
    * emitted by five observables.
    *
    * Similar with `combineLatest`, but only emits items when the single source
    * emits an item (not when any of the Observables that are passed to the operator
    * do, as combineLatest does).
    *
    * @param o1 is the first observable that gets paired with the source
    * @param o2 is the second observable that gets paired with the source
    * @param o3 is the third observable that gets paired with the source
    * @param o4 is the fourth observable that gets paired with the source
    * @param o5 is the fifth observable that gets paired with the source
    * @param f is a mapping function over the generated pairs
    */
  def withLatestFrom5[B1,B2,B3,B4,B5,R](
    o1: Observable[B1], o2: Observable[B2], o3: Observable[B3],
    o4: Observable[B4], o5: Observable[B5])
    (f: (A,B1,B2,B3,B4,B5) => R): Self[R] =
    self.transform(source =>
      source.withLatestFrom(Observable.combineLatest5(o1,o2,o3,o4,o5)) { (a, o) =>
        f(a,o._1,o._2,o._3,o._4,o._5)
      })

  /** Combines the elements emitted by the source with the latest elements
    * emitted by six observables.
    *
    * Similar with `combineLatest`, but only emits items when the single source
    * emits an item (not when any of the Observables that are passed to the operator
    * do, as combineLatest does).
    *
    * @param o1 is the first observable that gets paired with the source
    * @param o2 is the second observable that gets paired with the source
    * @param o3 is the third observable that gets paired with the source
    * @param o4 is the fourth observable that gets paired with the source
    * @param o5 is the fifth observable that gets paired with the source
    * @param o6 is the sixth observable that gets paired with the source
    * @param f is a mapping function over the generated pairs
    */
  def withLatestFrom6[B1,B2,B3,B4,B5,B6,R](
    o1: Observable[B1], o2: Observable[B2], o3: Observable[B3],
    o4: Observable[B4], o5: Observable[B5], o6: Observable[B6])
    (f: (A,B1,B2,B3,B4,B5,B6) => R): Self[R] =
    self.transform(source =>
      source.withLatestFrom(Observable.combineLatest6(o1,o2,o3,o4,o5,o6)) { (a, o) =>
        f(a,o._1,o._2,o._3,o._4,o._5,o._6)
      })

  /** Creates a new observable from this observable and another given
    * observable by combining their items in pairs in a strict sequence.
    *
    * So the first item emitted by the new observable will be the tuple of the
    * first items emitted by each of the source observables; the second item
    * emitted by the new observable will be a tuple with the second items
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatest]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    *
    * @param other is an observable that gets paired with the source
    * @return a new observable sequence that emits the paired items
    *         of the source observables
    */
  def zip[B](other: Observable[B]): Self[(A,B)] =
    self.transform(self => new Zip2Observable[A,B,(A,B)](self, other)((a,b) => (a,b)))

  /** Creates a new observable from this observable and another given
    * observable 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 item 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 item
    * emitted by each of those observables; and so forth.
    *
    * See [[combineLatestMap]] for a more relaxed alternative that doesn't
    * combine items in strict sequence.
    *
    * @param other is an observable that gets paired with the source
    * @param f is a mapping function over the generated pairs
    */
  def zipMap[B,R](other: Observable[B])(f: (A,B) => R): Self[R] =
    self.transform(self => new Zip2Observable[A,B,R](self, other)(f))

  /** Zips the emitted elements of the source with their indices. */
  def zipWithIndex: Self[(A, Long)] =
    self.liftByOperator(new ZipWithIndexOperator[A])
}

object ObservableLike {
  /** An `Operator` is a function for transforming observers,
    * that can be used for lifting observables.
    */
  type Operator[-I,+O] = Subscriber[O] => Subscriber[I]

  /** A `Transformer` is a function used for transforming observables */
  type Transformer[-A,+B] = Observable[A] => Observable[B]
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy