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