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

rx.lang.scala.Observable.scala Maven / Gradle / Ivy

/**
 * Copyright 2013 Netflix, Inc.
 *
 * 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 rx.lang.scala

import rx.util.functions.FuncN
import rx.Observable.OnSubscribeFunc
import rx.lang.scala.observables.ConnectableObservable


/**
 * The Observable interface that implements the Reactive Pattern.
 *
 * @define subscribeObserverMain
 * Call this method to subscribe an [[rx.lang.scala.Observer]] for receiving 
 * items and notifications from the Observable.
 *
 * A typical implementation of `subscribe` does the following:
 *
 * It stores a reference to the Observer in a collection object, such as a `List[T]` object.
 *
 * It returns a reference to the [[rx.lang.scala.Subscription]] interface. This enables Observers to
 * unsubscribe, that is, to stop receiving items and notifications before the Observable stops
 * sending them, which also invokes the Observer's [[rx.lang.scala.Observer.onCompleted onCompleted]] method.
 *
 * An `Observable[T]` instance is responsible for accepting all subscriptions
 * and notifying all Observers. Unless the documentation for a particular
 * `Observable[T]` implementation indicates otherwise, Observers should make no
 * assumptions about the order in which multiple Observers will receive their notifications.
 *
 * @define subscribeObserverParamObserver 
 *         the observer
 * @define subscribeObserverParamScheduler 
 *         the [[rx.lang.scala.Scheduler]] on which Observers subscribe to the Observable
 * @define subscribeAllReturn 
 *         a [[rx.lang.scala.Subscription]] reference whose `unsubscribe` method can be called to  stop receiving items
 *         before the Observable has finished sending them
 *
 * @define subscribeCallbacksMainWithNotifications
 * Call this method to receive items and notifications from this observable.
 *
 * @define subscribeCallbacksMainNoNotifications
 * Call this method to receive items from this observable.
 *
 * @define subscribeCallbacksParamOnNext 
 *         this function will be called whenever the Observable emits an item
 * @define subscribeCallbacksParamOnError
 *         this function will be called if an error occurs
 * @define subscribeCallbacksParamOnComplete
 *         this function will be called when this Observable has finished emitting items
 * @define subscribeCallbacksParamScheduler
 *         the scheduler to use
 *
 * @define debounceVsThrottle
 * Information on debounce vs throttle:
 *  - [[http://drupalmotion.com/article/debounce-and-throttle-visual-explanation]]
 *  - [[http://unscriptable.com/2009/03/20/debouncing-javascript-methods/]]
 *  - [[http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/]]
 *
 *
 */
trait Observable[+T]
{
  import scala.collection.Seq
  import scala.concurrent.duration.{Duration, TimeUnit}
  import rx.util.functions._
  import rx.lang.scala.observables.BlockingObservable
  import ImplicitFunctionConversions._
  import JavaConversions._

  private [scala] val asJavaObservable: rx.Observable[_ <: T]

  /**
   * $subscribeObserverMain
   *
   * @return $subscribeAllReturn
   */
  def subscribe(): Subscription = {
    asJavaObservable.subscribe()
  }

  /**
   * $subscribeObserverMain
   *
   * @param observer $subscribeObserverParamObserver
   * @param scheduler $subscribeObserverParamScheduler
   * @return $subscribeAllReturn
   */
  def subscribe(observer: Observer[T], scheduler: Scheduler): Subscription = {
    asJavaObservable.subscribe(observer.asJavaObserver, scheduler)
  }

  /**
   * $subscribeObserverMain
   *
   * @param observer $subscribeObserverParamObserver
   * @return $subscribeAllReturn
   */
  def subscribe(observer: Observer[T]): Subscription = {
    asJavaObservable.subscribe(observer.asJavaObserver)
  }

  /**
   * $subscribeObserverMain
   *
   * @param observer $subscribeObserverParamObserver
   * @return $subscribeAllReturn
   */
  def apply(observer: Observer[T]): Subscription = subscribe(observer)

  /**
   * $subscribeCallbacksMainNoNotifications
   *
   * @param onNext $subscribeCallbacksParamOnNext
   * @return $subscribeAllReturn
   */
  def subscribe(onNext: T => Unit): Subscription = {
   asJavaObservable.subscribe(scalaFunction1ProducingUnitToAction1(onNext))
  }

  /**
   * $subscribeCallbacksMainWithNotifications
   *
   * @param onNext $subscribeCallbacksParamOnNext
   * @param onError $subscribeCallbacksParamOnError
   * @return $subscribeAllReturn
   */
  def subscribe(onNext: T => Unit, onError: Throwable => Unit): Subscription = {
    asJavaObservable.subscribe(
      scalaFunction1ProducingUnitToAction1(onNext),
      scalaFunction1ProducingUnitToAction1(onError)
    )
  }

  /**
   * $subscribeCallbacksMainWithNotifications
   *
   * @param onNext $subscribeCallbacksParamOnNext
   * @param onError $subscribeCallbacksParamOnError
   * @param onCompleted $subscribeCallbacksParamOnComplete
   * @return $subscribeAllReturn
   */
  def subscribe(onNext: T => Unit, onError: Throwable => Unit, onCompleted: () => Unit): Subscription = {
    asJavaObservable.subscribe(
      scalaFunction1ProducingUnitToAction1(onNext),
      scalaFunction1ProducingUnitToAction1(onError), 
      scalaFunction0ProducingUnitToAction0(onCompleted)
    )
  }

  /**
   * $subscribeCallbacksMainWithNotifications
   *
   * @param onNext $subscribeCallbacksParamOnNext
   * @param onError $subscribeCallbacksParamOnError
   * @param onCompleted $subscribeCallbacksParamOnComplete
   * @param scheduler $subscribeCallbacksParamScheduler
   * @return $subscribeAllReturn
   */
  def subscribe(onNext: T => Unit, onError: Throwable => Unit, onCompleted: () => Unit, scheduler: Scheduler): Subscription = {
    asJavaObservable.subscribe(scalaFunction1ProducingUnitToAction1(onNext),
      scalaFunction1ProducingUnitToAction1(onError),
      scalaFunction0ProducingUnitToAction0(onCompleted),
      scheduler)
  }

  /**
   * $subscribeCallbacksMainWithNotifications
   *
   * @param onNext $subscribeCallbacksParamOnNext
   * @param onError $subscribeCallbacksParamOnError
   * @param scheduler $subscribeCallbacksParamScheduler
   * @return $subscribeAllReturn
   */
  def subscribe(onNext: T => Unit, onError: Throwable => Unit, scheduler: Scheduler): Subscription = {
    asJavaObservable.subscribe(
      scalaFunction1ProducingUnitToAction1(onNext),
      scalaFunction1ProducingUnitToAction1(onError),
      scheduler)
  }

  /**
   * $subscribeCallbacksMainNoNotifications
   *
   * @param onNext $subscribeCallbacksParamOnNext
   * @param scheduler $subscribeCallbacksParamScheduler
   * @return $subscribeAllReturn
   */
  def subscribe(onNext: T => Unit, scheduler: Scheduler): Subscription = {
    asJavaObservable.subscribe(scalaFunction1ProducingUnitToAction1(onNext), scheduler)
  }

  /**
   * Returns a pair of a start function and an [[rx.lang.scala.Observable]] that upon calling the start function causes the source Observable to
   * push results into the specified subject.
   *
   * @param subject
   *            the `rx.lang.scala.subjects.Subject` to push source items into
   * @return a pair of a start function and an [[rx.lang.scala.Observable]] such that when the start function
   *         is called, the Observable starts to push results into the specified Subject
   */
  def multicast[R >: T](subject: rx.lang.scala.Subject[R]): (() => Subscription, Observable[R]) = {
    val s: rx.subjects.Subject[_ >: T, _<: R] = subject.asJavaSubject
    val javaCO: rx.observables.ConnectableObservable[R] = asJavaObservable.multicast(s)
    (() => javaCO.connect(), toScalaObservable(javaCO))
  }

  /**
   * Returns an Observable that first emits the items emitted by `this`, and then the items emitted
   * by `that`.
   *
   * 
   *
   * @param that
   *            an Observable to be appended
   * @return an Observable that emits items that are the result of combining the items emitted by
   *         this and that, one after the other
   */
  def ++[U >: T](that: Observable[U]): Observable[U] = {
    val o1: rx.Observable[_ <: U] = this.asJavaObservable
    val o2: rx.Observable[_ <: U] = that.asJavaObservable
    toScalaObservable(rx.Observable.concat(o1, o2))
  }

  /**
   * Returns an Observable that emits the items emitted by several Observables, one after the
   * other.
   *
   * This operation is only available if `this` is of type `Observable[Observable[U]]` for some `U`,
   * otherwise you'll get a compilation error.
   *
   * @usecase def concat[U]: Observable[U]
   */
  def concat[U](implicit evidence: Observable[T] <:< Observable[Observable[U]]): Observable[U] = {
    val o2: Observable[Observable[U]] = this
    val o3: Observable[rx.Observable[_ <: U]] = o2.map(_.asJavaObservable)
    val o4: rx.Observable[_ <: rx.Observable[_ <: U]] = o3.asJavaObservable
    val o5 = rx.Observable.concat[U](o4)
    toScalaObservable[U](o5)
  }

  /**
   * Wraps this Observable in another Observable that ensures that the resulting
   * Observable is chronologically well-behaved.
   *
   * 
   *
   * A well-behaved Observable does not interleave its invocations of the [[rx.lang.scala.Observer.onNext onNext]], [[rx.lang.scala.Observer.onCompleted onCompleted]], and [[rx.lang.scala.Observer.onError onError]] methods of
   * its [[rx.lang.scala.Observer]]s; it invokes `onCompleted` or `onError` only once; and it never invokes `onNext` after invoking either `onCompleted` or `onError`.
   * `synchronize` enforces this, and the Observable it returns invokes `onNext` and `onCompleted` or `onError` synchronously.
   *
   * @return an Observable that is a chronologically well-behaved version of the source
   *         Observable, and that synchronously notifies its [[rx.lang.scala.Observer]]s
   */
  def synchronize: Observable[T] = {
    toScalaObservable[T](asJavaObservable.synchronize)
  }

  /**
   * Wraps each item emitted by a source Observable in a timestamped tuple.
   *
   * 
   *
   * @return an Observable that emits timestamped items from the source Observable
   */
  def timestamp: Observable[(Long, T)] = {
    toScalaObservable[rx.util.Timestamped[_ <: T]](asJavaObservable.timestamp())
      .map((t: rx.util.Timestamped[_ <: T]) => (t.getTimestampMillis, t.getValue))
  }

  /**
   * Returns an Observable formed from this Observable and another Observable by combining 
   * corresponding elements in pairs. 
   * The number of `onNext` invocations of the resulting `Observable[(T, U)]`
   * is the minumum of the number of `onNext` invocations of `this` and `that`. 
   */
  def zip[U](that: Observable[U]): Observable[(T, U)] = {
    zip(that, (t: T, u: U) => (t, u))
  }

  /**
   * Returns an Observable formed from this Observable and another Observable by combining
   * corresponding elements using the selector function.
   * The number of `onNext` invocations of the resulting `Observable[(T, U)]`
   * is the minumum of the number of `onNext` invocations of `this` and `that`.
   *
   * Note that this function is private because Scala collections don't have such a function.
   */
  private def zip[U, R](that: Observable[U], selector: (T,U) => R): Observable[R] = {
    toScalaObservable[R](rx.Observable.zip[T, U, R](this.asJavaObservable, that.asJavaObservable, selector))
  }

  /**
   * Zips this Observable with its indices.
   *
   * @return An Observable emitting pairs consisting of all elements of this Observable paired with 
   *         their index. Indices start at 0.
   */
  def zipWithIndex: Observable[(T, Int)] = {
    val fScala: (T, Integer) => (T, Int) = (elem: T, index: Integer) => (elem, index)
    val fJava : Func2[_ >: T, Integer, _ <: (T, Int)] = fScala
    toScalaObservable[(T, Int)](asJavaObservable.mapWithIndex[(T, Int)](fJava))
  }

  /**
   * Creates an Observable which produces buffers of collected values.
   *
   * This Observable produces connected non-overlapping buffers. The current buffer is
   * emitted and replaced with a new buffer when the Observable produced by the specified function produces an object. The function will then
   * be used to create a new Observable to listen for the end of the next buffer.
   *
   * @param closings
   *            The function which is used to produce an [[rx.lang.scala.Observable]] for every buffer created.
   *            When this [[rx.lang.scala.Observable]] produces an object, the associated buffer
   *            is emitted and replaced with a new one.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping buffers, which are emitted
   *         when the current [[rx.lang.scala.Observable]] created with the function argument produces an object.
   */
  def buffer[Closing](closings: () => Observable[_ <: Closing]) : Observable[Seq[T]] = {
    val f: Func0[_ <: rx.Observable[_ <: Closing]] = closings().asJavaObservable
    val jObs: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer[Closing](f)
    Observable.jObsOfListToScObsOfSeq(jObs.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }
  /**
   * Creates an Observable which produces buffers of collected values.
   *
   * This Observable produces buffers. Buffers are created when the specified `openings`
   * Observable produces an object. Additionally the function argument
   * is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. When this
   * Observable produces such an object, the associated buffer is emitted.
   *
   * @param openings
   *            The [[rx.lang.scala.Observable]] which, when it produces an object, will cause
   *            another buffer to be created.
   * @param closings
   *            The function which is used to produce an [[rx.lang.scala.Observable]] for every buffer created.
   *            When this [[rx.lang.scala.Observable]] produces an object, the associated buffer
   *            is emitted.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces buffers which are created and emitted when the specified [[rx.lang.scala.Observable]]s publish certain objects.
   */
  def buffer[Opening, Closing](openings: Observable[Opening], closings: Opening => Observable[Closing]): Observable[Seq[T]] = {
    val opening: rx.Observable[_ <: Opening] = openings.asJavaObservable
    val closing: Func1[_ >: Opening, _ <: rx.Observable[_ <: Closing]] = (o: Opening) => closings(o).asJavaObservable
    val jObs: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer[Opening, Closing](opening, closing)
    Observable.jObsOfListToScObsOfSeq(jObs.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }

  /**
   * Creates an Observable which produces buffers of collected values.
   *
   * This Observable produces connected non-overlapping buffers, each containing `count`
   * elements. When the source Observable completes or encounters an error, the current
   * buffer is emitted, and the event is propagated.
   *
   * @param count
   *            The maximum size of each buffer before it should be emitted.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping buffers containing at most
   *         `count` produced values.
   */
  def buffer(count: Int): Observable[Seq[T]] = {
    val oJava: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer(count)
    Observable.jObsOfListToScObsOfSeq(oJava.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }

  /**
   * Creates an Observable which produces buffers of collected values.
   *
   * This Observable produces buffers every `skip` values, each containing `count`
   * elements. When the source Observable completes or encounters an error, the current
   * buffer is emitted, and the event is propagated.
   *
   * @param count
   *            The maximum size of each buffer before it should be emitted.
   * @param skip
   *            How many produced values need to be skipped before starting a new buffer. Note that when `skip` and
   *            `count` are equals that this is the same operation as `buffer(int)`.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces buffers every `skip` values containing at most
   *         `count` produced values.
   */
  def buffer(count: Int, skip: Int): Observable[Seq[T]] = {
    val oJava: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer(count, skip)
    Observable.jObsOfListToScObsOfSeq(oJava.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }

  /**
   * Creates an Observable which produces buffers of collected values.
   *
   * This Observable produces connected non-overlapping buffers, each of a fixed duration
   * specified by the `timespan` argument. When the source Observable completes or encounters
   * an error, the current buffer is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each buffer is collecting values before it should be emitted, and
   *            replaced with a new buffer.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping buffers with a fixed duration.
   */
  def buffer(timespan: Duration): Observable[Seq[T]] = {
    val oJava: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer(timespan.length, timespan.unit)
    Observable.jObsOfListToScObsOfSeq(oJava.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }

  /**
   * Creates an Observable which produces buffers of collected values.
   *
   * This Observable produces connected non-overlapping buffers, each of a fixed duration
   * specified by the `timespan` argument. When the source Observable completes or encounters
   * an error, the current buffer is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each buffer is collecting values before it should be emitted, and
   *            replaced with a new buffer.
   * @param scheduler
   *            The [[rx.lang.scala.Scheduler]] to use when determining the end and start of a buffer.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping buffers with a fixed duration.
   */
  def buffer(timespan: Duration, scheduler: Scheduler): Observable[Seq[T]] = {
    val oJava: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer(timespan.length, timespan.unit, scheduler)
    Observable.jObsOfListToScObsOfSeq(oJava.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }

  /**
   * Creates an Observable which produces buffers of collected values. This Observable produces connected
   * non-overlapping buffers, each of a fixed duration specified by the `timespan` argument or a maximum size
   * specified by the `count` argument (which ever is reached first). When the source Observable completes
   * or encounters an error, the current buffer is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each buffer is collecting values before it should be emitted, and
   *            replaced with a new buffer.
   * @param count
   *            The maximum size of each buffer before it should be emitted.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping buffers which are emitted after
   *         a fixed duration or when the buffer has reached maximum capacity (which ever occurs first).
   */
  def buffer(timespan: Duration, count: Int): Observable[Seq[T]] = {
    val oJava: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer(timespan.length, timespan.unit, count)
    Observable.jObsOfListToScObsOfSeq(oJava.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }

  /**
   * Creates an Observable which produces buffers of collected values. This Observable produces connected
   * non-overlapping buffers, each of a fixed duration specified by the `timespan` argument or a maximum size
   * specified by the `count` argument (which ever is reached first). When the source Observable completes
   * or encounters an error, the current buffer is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each buffer is collecting values before it should be emitted, and
   *            replaced with a new buffer.
   * @param count
   *            The maximum size of each buffer before it should be emitted.
   * @param scheduler
   *            The [[rx.lang.scala.Scheduler]] to use when determining the end and start of a buffer.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping buffers which are emitted after
   *         a fixed duration or when the buffer has reached maximum capacity (which ever occurs first).
   */
  def buffer(timespan: Duration, count: Int, scheduler: Scheduler): Observable[Seq[T]] = {
    val oJava: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer(timespan.length, timespan.unit, count, scheduler)
    Observable.jObsOfListToScObsOfSeq(oJava.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }

  /**
   * Creates an Observable which produces buffers of collected values. This Observable starts a new buffer
   * periodically, which is determined by the `timeshift` argument. Each buffer is emitted after a fixed timespan
   * specified by the `timespan` argument. When the source Observable completes or encounters an error, the
   * current buffer is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each buffer is collecting values before it should be emitted.
   * @param timeshift
   *            The period of time after which a new buffer will be created.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces new buffers periodically, and these are emitted after
   *         a fixed timespan has elapsed.
   */
  def buffer(timespan: Duration, timeshift: Duration): Observable[Seq[T]] = {
    val span: Long = timespan.length
    val shift: Long = timespan.unit.convert(timeshift.length, timeshift.unit)
    val unit: TimeUnit = timespan.unit
    val oJava: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer(span, shift, unit)
    Observable.jObsOfListToScObsOfSeq(oJava.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }

  /**
   * Creates an Observable which produces buffers of collected values. This Observable starts a new buffer
   * periodically, which is determined by the `timeshift` argument. Each buffer is emitted after a fixed timespan
   * specified by the `timespan` argument. When the source Observable completes or encounters an error, the
   * current buffer is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each buffer is collecting values before it should be emitted.
   * @param timeshift
   *            The period of time after which a new buffer will be created.
   * @param scheduler
   *            The [[rx.lang.scala.Scheduler]] to use when determining the end and start of a buffer.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces new buffers periodically, and these are emitted after
   *         a fixed timespan has elapsed.
   */
  def buffer(timespan: Duration, timeshift: Duration, scheduler: Scheduler): Observable[Seq[T]] = {
    val span: Long = timespan.length
    val shift: Long = timespan.unit.convert(timeshift.length, timeshift.unit)
    val unit: TimeUnit = timespan.unit
    val oJava: rx.Observable[_ <: java.util.List[_]] = asJavaObservable.buffer(span, shift, unit, scheduler)
    Observable.jObsOfListToScObsOfSeq(oJava.asInstanceOf[rx.Observable[_ <: java.util.List[T]]])
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable produces connected
   * non-overlapping windows. The current window is emitted and replaced with a new window when the
   * Observable produced by the specified function produces an object. 
   * The function will then be used to create a new Observable to listen for the end of the next
   * window.
   *
   * @param closings
   *            The function which is used to produce an [[rx.lang.scala.Observable]] for every window created.
   *            When this [[rx.lang.scala.Observable]] produces an object, the associated window
   *            is emitted and replaced with a new one.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping windows, which are emitted
   *         when the current [[rx.lang.scala.Observable]] created with the function argument produces an object.
   */
  def window[Closing](closings: () => Observable[Closing]): Observable[Observable[T]] = {
    val func : Func0[_ <: rx.Observable[_ <: Closing]] = closings().asJavaObservable
    val o1: rx.Observable[_ <: rx.Observable[_]] = asJavaObservable.window[Closing](func)
    val o2 = Observable.items(o1).map((x: rx.Observable[_]) => {
      val x2 = x.asInstanceOf[rx.Observable[_ <: T]]
      toScalaObservable[T](x2)
    })
    o2
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable produces windows.
   * Chunks are created when the specified `openings` Observable produces an object.
   * Additionally the `closings` argument is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. 
   * When this Observable produces such an object, the associated window is emitted.
   *
   * @param openings
   *            The [[rx.lang.scala.Observable]] which when it produces an object, will cause
   *            another window to be created.
   * @param closings
   *            The function which is used to produce an [[rx.lang.scala.Observable]] for every window created.
   *            When this [[rx.lang.scala.Observable]] produces an object, the associated window
   *            is emitted.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces windows which are created and emitted when the specified [[rx.lang.scala.Observable]]s publish certain objects.
   */
  def window[Opening, Closing](openings: Observable[Opening], closings: Opening => Observable[Closing]) = {
    Observable.jObsOfJObsToScObsOfScObs(
      asJavaObservable.window[Opening, Closing](openings.asJavaObservable, (op: Opening) => closings(op).asJavaObservable))
      : Observable[Observable[T]] // SI-7818
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable produces connected
   * non-overlapping windows, each containing `count` elements. When the source Observable completes or
   * encounters an error, the current window is emitted, and the event is propagated.
   *
   * @param count
   *            The maximum size of each window before it should be emitted.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping windows containing at most
   *         `count` produced values.
   */
  def window(count: Int): Observable[Observable[T]] = {
    // this unnecessary ascription is needed because of this bug (without, compiler crashes):
    // https://issues.scala-lang.org/browse/SI-7818
    Observable.jObsOfJObsToScObsOfScObs(asJavaObservable.window(count)) : Observable[Observable[T]]
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable produces windows every
   * `skip` values, each containing `count` elements. When the source Observable completes or encounters an error,
   * the current window is emitted and the event is propagated.
   *
   * @param count
   *            The maximum size of each window before it should be emitted.
   * @param skip
   *            How many produced values need to be skipped before starting a new window. Note that when `skip` and
   *            `count` are equal that this is the same operation as `window(int)`.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces windows every `skip` values containing at most
   *         `count` produced values.
   */
  def window(count: Int, skip: Int): Observable[Observable[T]] = {
    Observable.jObsOfJObsToScObsOfScObs(asJavaObservable.window(count, skip))
      : Observable[Observable[T]] // SI-7818
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable produces connected
   * non-overlapping windows, each of a fixed duration specified by the `timespan` argument. When the source
   * Observable completes or encounters an error, the current window is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each window is collecting values before it should be emitted, and
   *            replaced with a new window.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping windows with a fixed duration.
   */
  def window(timespan: Duration): Observable[Observable[T]] = {
    Observable.jObsOfJObsToScObsOfScObs(asJavaObservable.window(timespan.length, timespan.unit))
      : Observable[Observable[T]] // SI-7818
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable produces connected
   * non-overlapping windows, each of a fixed duration specified by the `timespan` argument. When the source
   * Observable completes or encounters an error, the current window is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each window is collecting values before it should be emitted, and
   *            replaced with a new window.
   * @param scheduler
   *            The [[rx.lang.scala.Scheduler]] to use when determining the end and start of a window.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping windows with a fixed duration.
   */
  def window(timespan: Duration, scheduler: Scheduler): Observable[Observable[T]] = {
    Observable.jObsOfJObsToScObsOfScObs(asJavaObservable.window(timespan.length, timespan.unit, scheduler))
      : Observable[Observable[T]] // SI-7818
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable produces connected
   * non-overlapping windows, each of a fixed duration specified by the `timespan` argument or a maximum size
   * specified by the `count` argument (which ever is reached first). When the source Observable completes
   * or encounters an error, the current window is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each window is collecting values before it should be emitted, and
   *            replaced with a new window.
   * @param count
   *            The maximum size of each window before it should be emitted.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping windows which are emitted after
   *         a fixed duration or when the window has reached maximum capacity (which ever occurs first).
   */
  def window(timespan: Duration, count: Int): Observable[Observable[T]] = {
    Observable.jObsOfJObsToScObsOfScObs(asJavaObservable.window(timespan.length, timespan.unit, count))
      : Observable[Observable[T]] // SI-7818
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable produces connected
   * non-overlapping windows, each of a fixed duration specified by the `timespan` argument or a maximum size
   * specified by the `count` argument (which ever is reached first). When the source Observable completes
   * or encounters an error, the current window is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each window is collecting values before it should be emitted, and
   *            replaced with a new window.
   * @param count
   *            The maximum size of each window before it should be emitted.
   * @param scheduler
   *            The [[rx.lang.scala.Scheduler]] to use when determining the end and start of a window.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces connected non-overlapping windows which are emitted after
   *         a fixed duration or when the window has reached maximum capacity (which ever occurs first).
   */
  def window(timespan: Duration, count: Int, scheduler: Scheduler): Observable[Observable[T]] = {
    Observable.jObsOfJObsToScObsOfScObs(asJavaObservable.window(timespan.length, timespan.unit, count, scheduler))
      : Observable[Observable[T]] // SI-7818
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable starts a new window
   * periodically, which is determined by the `timeshift` argument. Each window is emitted after a fixed timespan
   * specified by the `timespan` argument. When the source Observable completes or encounters an error, the
   * current window is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each window is collecting values before it should be emitted.
   * @param timeshift
   *            The period of time after which a new window will be created.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces new windows periodically, and these are emitted after
   *         a fixed timespan has elapsed.
   */
  def window(timespan: Duration, timeshift: Duration): Observable[Observable[T]] = {
    val span: Long = timespan.length
    val shift: Long = timespan.unit.convert(timeshift.length, timeshift.unit)
    val unit: TimeUnit = timespan.unit
    Observable.jObsOfJObsToScObsOfScObs(asJavaObservable.window(span, shift, unit))
      : Observable[Observable[T]] // SI-7818
  }

  /**
   * Creates an Observable which produces windows of collected values. This Observable starts a new window
   * periodically, which is determined by the `timeshift` argument. Each window is emitted after a fixed timespan
   * specified by the `timespan` argument. When the source Observable completes or encounters an error, the
   * current window is emitted and the event is propagated.
   *
   * @param timespan
   *            The period of time each window is collecting values before it should be emitted.
   * @param timeshift
   *            The period of time after which a new window will be created.
   * @param scheduler
   *            The [[rx.lang.scala.Scheduler]] to use when determining the end and start of a window.
   * @return
   *         An [[rx.lang.scala.Observable]] which produces new windows periodically, and these are emitted after
   *         a fixed timespan has elapsed.
   */
  def window(timespan: Duration, timeshift: Duration, scheduler: Scheduler): Observable[Observable[T]] = {
    val span: Long = timespan.length
    val shift: Long = timespan.unit.convert(timeshift.length, timeshift.unit)
    val unit: TimeUnit = timespan.unit
    Observable.jObsOfJObsToScObsOfScObs(asJavaObservable.window(span, shift, unit, scheduler))
      : Observable[Observable[T]] // SI-7818
  }

  /**
   * Returns an Observable which only emits those items for which a given predicate holds.
   *
   * 
   *
   * @param predicate
   *            a function that evaluates the items emitted by the source Observable, returning `true` if they pass the filter
   * @return an Observable that emits only those items in the original Observable that the filter
   *         evaluates as `true`
   */
  def filter(predicate: T => Boolean): Observable[T] = {
    toScalaObservable[T](asJavaObservable.filter(predicate))
  }

  /**
   * Registers an function to be called when this Observable invokes [[rx.lang.scala.Observer.onCompleted onCompleted]] or [[rx.lang.scala.Observer.onError onError]].
   *
   * 
   *
   * @param action
   *            an function to be invoked when the source Observable finishes
   * @return an Observable that emits the same items as the source Observable, then invokes the function
   */
  def finallyDo(action: () => Unit): Observable[T] = {
    toScalaObservable[T](asJavaObservable.finallyDo(action))
  }

  /**
   * 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 Observables and emitting the results of this merger.
   *
   * 
   *
   * @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 merging the results of the Observables
   *         obtained from this transformation.
   */
  def flatMap[R](f: T => Observable[R]): Observable[R] = {
    toScalaObservable[R](asJavaObservable.flatMap[R](new Func1[T, rx.Observable[_ <: R]]{
      def call(t1: T): rx.Observable[_ <: R] = { f(t1).asJavaObservable }
    }))
  }

  /**
   * Returns an Observable that applies the given function to each item emitted by an
   * Observable and emits the result.
   *
   * 
   *
   * @param func
   *            a function to apply to each item emitted by the Observable
   * @return an Observable that emits the items from the source Observable, transformed by the
   *         given function
   */
  def map[R](func: T => R): Observable[R] = {
    toScalaObservable[R](asJavaObservable.map[R](new Func1[T,R] {
      def call(t1: T): R = func(t1)
    }))
  }

  /**
   * Turns all of the notifications from a source Observable into [[rx.lang.scala.Observer.onNext onNext]] emissions,
   * and marks them with their original notification types within [[rx.lang.scala.Notification]] objects.
   *
   * 
   *
   * @return an Observable whose items are the result of materializing the items and
   *         notifications of the source Observable
   */
  def materialize: Observable[Notification[T]] = {
    toScalaObservable[rx.Notification[_ <: T]](asJavaObservable.materialize()).map(Notification(_))
  }

  /**
   * Asynchronously subscribes and unsubscribes Observers on the specified [[rx.lang.scala.Scheduler]].
   *
   * 
   *
   * @param scheduler
   *            the [[rx.lang.scala.Scheduler]] to perform subscription and unsubscription actions on
   * @return the source Observable modified so that its subscriptions and unsubscriptions happen
   *         on the specified [[rx.lang.scala.Scheduler]]
   */
  def subscribeOn(scheduler: Scheduler): Observable[T] = {
    toScalaObservable[T](asJavaObservable.subscribeOn(scheduler))
  }

  /**
   * Asynchronously notify [[rx.lang.scala.Observer]]s on the specified [[rx.lang.scala.Scheduler]].
   *
   * 
   *
   * @param scheduler
   *            the [[rx.lang.scala.Scheduler]] to notify [[rx.lang.scala.Observer]]s on
   * @return the source Observable modified so that its [[rx.lang.scala.Observer]]s are notified on the
   *         specified [[rx.lang.scala.Scheduler]]
   */
  def observeOn(scheduler: Scheduler): Observable[T] = {
    toScalaObservable[T](asJavaObservable.observeOn(scheduler))
  }

  /**
   * Returns an Observable that reverses the effect of [[rx.lang.scala.Observable.materialize]] by
   * transforming the [[rx.lang.scala.Notification]] objects emitted by the source Observable into the items
   * or notifications they represent.
   *
   * This operation is only available if `this` is of type `Observable[Notification[U]]` for some `U`, 
   * otherwise you will get a compilation error.
   *
   * 
   *
   * @return an Observable that emits the items and notifications embedded in the [[rx.lang.scala.Notification]] objects emitted by the source Observable
   *
   * @usecase def dematerialize[U]: Observable[U]
   *   @inheritdoc
   *
   */
  // with =:= it does not work, why?
  def dematerialize[U](implicit evidence: Observable[T] <:< Observable[Notification[U]]): Observable[U] = {
    val o1: Observable[Notification[U]] = this
    val o2: Observable[rx.Notification[_ <: U]] = o1.map(_.asJavaNotification)
    val o3 = o2.asJavaObservable.dematerialize[U]()
    toScalaObservable[U](o3)
  }

  /**
   * Instruct an Observable to pass control to another Observable rather than invoking [[rx.lang.scala.Observer.onError onError]] if it encounters an error.
   *
   * 
   *
   * By default, when an Observable encounters an error that prevents it from emitting the
   * expected item to its [[rx.lang.scala.Observer]], the Observable invokes its Observer's
   * `onError` method, and then quits without invoking any more of its Observer's
   * methods. The `onErrorResumeNext` method changes this behavior. If you pass a
   * function that returns an Observable (`resumeFunction`) to
   * `onErrorResumeNext`, if the original Observable encounters an error, instead of
   * invoking its Observer's `onError` method, it will instead relinquish control to
   * the Observable returned from `resumeFunction`, which will invoke the Observer's 
   * [[rx.lang.scala.Observer.onNext onNext]] method if it is able to do so. In such a case, because no
   * Observable necessarily invokes `onError`, the Observer may never know that an
   * error happened.
   *
   * You can use this to prevent errors from propagating or to supply fallback data should errors
   * be encountered.
   *
   * @param resumeFunction
   *            a function that returns an Observable that will take over if the source Observable
   *            encounters an error
   * @return the original Observable, with appropriately modified behavior
   */
  def onErrorResumeNext[U >: T](resumeFunction: Throwable => Observable[U]): Observable[U] = {
    val f: Func1[Throwable, rx.Observable[_ <: U]] = (t: Throwable) => resumeFunction(t).asJavaObservable
    val f2 = f.asInstanceOf[Func1[Throwable, rx.Observable[Nothing]]]
    toScalaObservable[U](asJavaObservable.onErrorResumeNext(f2))
  }

  /**
   * Instruct an Observable to pass control to another Observable rather than invoking [[rx.lang.scala.Observer.onError onError]] if it encounters an error.
   *
   * 
   *
   * By default, when an Observable encounters an error that prevents it from emitting the
   * expected item to its [[rx.lang.scala.Observer]], the Observable invokes its Observer's
   * `onError` method, and then quits without invoking any more of its Observer's
   * methods. The `onErrorResumeNext` method changes this behavior. If you pass
   * another Observable (`resumeSequence`) to an Observable's
   * `onErrorResumeNext` method, if the original Observable encounters an error,
   * instead of invoking its Observer's `onError` method, it will instead relinquish
   * control to `resumeSequence` which will invoke the Observer's [[rx.lang.scala.Observer.onNext onNext]]
   * method if it is able to do so. In such a case, because no
   * Observable necessarily invokes `onError`, the Observer may never know that an
   * error happened.
   *
   * You can use this to prevent errors from propagating or to supply fallback data should errors
   * be encountered.
   *
   * @param resumeSequence
   *            a function that returns an Observable that will take over if the source Observable
   *            encounters an error
   * @return the original Observable, with appropriately modified behavior
   */
  def onErrorResumeNext[U >: T](resumeSequence: Observable[U]): Observable[U] = {
    val rSeq1: rx.Observable[_ <: U] = resumeSequence.asJavaObservable
    val rSeq2: rx.Observable[Nothing] = rSeq1.asInstanceOf[rx.Observable[Nothing]]
    toScalaObservable[U](asJavaObservable.onErrorResumeNext(rSeq2))
  }

  /**
   * Instruct an Observable to pass control to another Observable rather than invoking [[rx.lang.scala.Observer.onError onError]] if it encounters an error of type `java.lang.Exception`.
   *
   * This differs from `Observable.onErrorResumeNext` in that this one does not handle `java.lang.Throwable` or `java.lang.Error` but lets those continue through.
   *
   * 
   *
   * By default, when an Observable encounters an error that prevents it from emitting the
   * expected item to its [[rx.lang.scala.Observer]], the Observable invokes its Observer's
   * `onError` method, and then quits without invoking any more of its Observer's
   * methods. The `onErrorResumeNext` method changes this behavior. If you pass
   * another Observable (`resumeSequence`) to an Observable's
   * `onErrorResumeNext` method, if the original Observable encounters an error,
   * instead of invoking its Observer's `onError` method, it will instead relinquish
   * control to `resumeSequence` which will invoke the Observer's [[rx.lang.scala.Observer.onNext onNext]]
   * method if it is able to do so. In such a case, because no
   * Observable necessarily invokes `onError`, the Observer may never know that an
   * error happened.
   *
   * You can use this to prevent errors from propagating or to supply fallback data should errors
   * be encountered.
   *
   * @param resumeSequence
   *            a function that returns an Observable that will take over if the source Observable
   *            encounters an error
   * @return the original Observable, with appropriately modified behavior
   */
  def onExceptionResumeNext[U >: T](resumeSequence: Observable[U]): Observable[U] = {
    val rSeq1: rx.Observable[_ <: U] = resumeSequence.asJavaObservable
    val rSeq2: rx.Observable[Nothing] = rSeq1.asInstanceOf[rx.Observable[Nothing]]
    toScalaObservable[U](asJavaObservable.onExceptionResumeNext(rSeq2))
  }

  /**
   * Instruct an Observable to emit an item (returned by a specified function) rather than
   * invoking [[rx.lang.scala.Observer.onError onError]] if it encounters an error.
   *
   * 
   *
   * By default, when an Observable encounters an error that prevents it from emitting the
   * expected item to its [[rx.lang.scala.Observer]], the Observable invokes its Observer's
   * `onError` method, and then quits without invoking any more of its Observer's
   * methods. The `onErrorReturn` method changes this behavior. If you pass a function
   * (`resumeFunction`) to an Observable's `onErrorReturn` method, if the
   * original Observable encounters an error, instead of invoking its Observer's
   * `onError` method, it will instead pass the return value of
   * `resumeFunction` to the Observer's [[rx.lang.scala.Observer.onNext onNext]] method.
   *
   * You can use this to prevent errors from propagating or to supply fallback data should errors
   * be encountered.
   *
   * @param resumeFunction
   *            a function that returns an item that the new Observable will emit if the source
   *            Observable encounters an error
   * @return the original Observable with appropriately modified behavior
   */
  def onErrorReturn[U >: T](resumeFunction: Throwable => U): Observable[U] = {
    val f1: Func1[Throwable, _ <: U] = resumeFunction
    val f2 = f1.asInstanceOf[Func1[Throwable, Nothing]]
    toScalaObservable[U](asJavaObservable.onErrorReturn(f2))
  }

  /**
   * Returns an Observable that applies a function of your choosing to the first item emitted by a
   * source Observable, then feeds the result of that function along with the second item emitted
   * by the source Observable into the same function, and so on until all items have been emitted
   * by the source Observable, and emits the final result from the final call to your function as
   * its sole item.
   *
   * 
   *
   * This technique, which is called "reduce" or "aggregate" here, is sometimes called "fold,"
   * "accumulate," "compress," or "inject" in other programming contexts. Groovy, for instance,
   * has an `inject` method that does a similar operation on lists.
   *
   * @param accumulator
   *            An accumulator function to be invoked on each item emitted by the source
   *            Observable, whose result will be used in the next accumulator call
   * @return an Observable that emits a single item that is the result of accumulating the
   *         output from the source Observable
   */
  def reduce[U >: T](accumulator: (U, U) => U): Observable[U] = {
    val func: Func2[_ >: U, _ >: U, _ <: U] = accumulator
    val func2 = func.asInstanceOf[Func2[T, T, T]]
    toScalaObservable[U](asJavaObservable.asInstanceOf[rx.Observable[T]].reduce(func2))
  }

  /**
   * Returns a pair of a start function and an [[rx.lang.scala.Observable]] that shares a single subscription to the underlying
   * Observable that will replay all of its items and notifications to any future [[rx.lang.scala.Observer]].
   *
   * 
   *
   * @return a pair of a start function and an [[rx.lang.scala.Observable]] such that when the start function
   *         is called, the Observable starts to emit items to its [[rx.lang.scala.Observer]]s
   */
  def replay: (() => Subscription, Observable[T]) = {
    val javaCO = asJavaObservable.replay()
    (() => javaCO.connect(), toScalaObservable[T](javaCO))
  }

  /**
   * This method has similar behavior to [[rx.lang.scala.Observable.replay]] except that this auto-subscribes to
   * the source Observable rather than returning a start function and an Observable.
   *
   * 
   *
   * This is useful when you want an Observable to cache responses and you can't control the
   * subscribe/unsubscribe behavior of all the [[rx.lang.scala.Observer]]s.
   *
   * When you call `cache`, it does not yet subscribe to the
   * source Observable. This only happens when `subscribe` is called
   * the first time on the Observable returned by `cache()`.
   * 
   * Note: You sacrifice the ability to unsubscribe from the origin when you use the
   * `cache()` operator so be careful not to use this operator on Observables that
   * emit an infinite or very large number of items that will use up memory.
   *
   * @return an Observable that when first subscribed to, caches all of its notifications for
   *         the benefit of subsequent subscribers.
   */
  def cache: Observable[T] = {
    toScalaObservable[T](asJavaObservable.cache())
  }

  /**
   * Returns a a pair of a start function and an [[rx.lang.scala.Observable]], which waits until the start function is called before it begins emitting
   * items to those [[rx.lang.scala.Observer]]s that have subscribed to it.
   *
   * 
   *
   * @return an [[rx.lang.scala.observables.ConnectableObservable]].
   */
  def publish: ConnectableObservable[T] = {
    new ConnectableObservable[T](asJavaObservable.publish())
  }

  // TODO add Scala-like aggregate function

  /**
   * Returns an Observable that applies a function of your choosing to the first item emitted by a
   * source Observable, then feeds the result of that function along with the second item emitted
   * by an Observable into the same function, and so on until all items have been emitted by the
   * source Observable, emitting the final result from the final call to your function as its sole
   * item.
   *
   * 
   *
   * This technique, which is called "reduce" or "aggregate" here, is sometimes called "fold,"
   * "accumulate," "compress," or "inject" in other programming contexts. Groovy, for instance,
   * has an `inject` method that does a similar operation on lists.
   *
   * @param initialValue
   *            the initial (seed) accumulator value
   * @param accumulator
   *            an accumulator function to be invoked on each item emitted by the source
   *            Observable, the result of which will be used in the next accumulator call
   * @return an Observable that emits a single item that is the result of accumulating the output
   *         from the items emitted by the source Observable
   */
  def foldLeft[R](initialValue: R)(accumulator: (R, T) => R): Observable[R] = {
    toScalaObservable[R](asJavaObservable.reduce(initialValue, new Func2[R,T,R]{
      def call(t1: R, t2: T): R = accumulator(t1,t2)
    }))
  }

  /**
   * Returns an Observable that emits the results of sampling the items emitted by the source
   * Observable at a specified time interval.
   *
   * 
   *
   * @param duration the sampling rate
   * @return an Observable that emits the results of sampling the items emitted by the source
   *         Observable at the specified time interval
   */
  def sample(duration: Duration): Observable[T] = {
    toScalaObservable[T](asJavaObservable.sample(duration.length, duration.unit))
  }

  /**
   * Returns an Observable that emits the results of sampling the items emitted by the source
   * Observable at a specified time interval.
   *
   * 
   *
   * @param duration the sampling rate
   * @param scheduler
   *            the [[rx.lang.scala.Scheduler]] to use when sampling
   * @return an Observable that emits the results of sampling the items emitted by the source
   *         Observable at the specified time interval
   */
  def sample(duration: Duration, scheduler: Scheduler): Observable[T] = {
    toScalaObservable[T](asJavaObservable.sample(duration.length, duration.unit, scheduler))
  }

  /**
   * Returns an Observable that applies a function of your choosing to the first item emitted by a
   * source Observable, then feeds the result of that function along with the second item emitted
   * by an Observable into the same function, and so on until all items have been emitted by the
   * source Observable, emitting the result of each of these iterations.
   *
   * 
   *
   * This sort of function is sometimes called an accumulator.
   *
   * Note that when you pass a seed to `scan()` the resulting Observable will emit
   * that seed as its first emitted item.
   *
   * @param initialValue
   *            the initial (seed) accumulator value
   * @param accumulator
   *            an accumulator function to be invoked on each item emitted by the source
   *            Observable, whose result will be emitted to [[rx.lang.scala.Observer]]s via
   *            [[rx.lang.scala.Observer.onNext onNext]] and used in the next accumulator call.
   * @return an Observable that emits the results of each call to the accumulator function
   */
  def scan[R](initialValue: R)(accumulator: (R, T) => R): Observable[R] = {
    toScalaObservable[R](asJavaObservable.scan(initialValue, new Func2[R,T,R]{
      def call(t1: R, t2: T): R = accumulator(t1,t2)
    }))
  }

  /**
   * Returns an Observable that applies a function of your choosing to the
   * first item emitted by a source Observable, then feeds the result of that
   * function along with the second item emitted by an Observable into the
   * same function, and so on until all items have been emitted by the source
   * Observable, emitting the result of each of these iterations.
   * 

* *

* * @param accumulator * an accumulator function to be invoked on each item emitted by the source * Observable, whose result will be emitted to [[rx.lang.scala.Observer]]s via * [[rx.lang.scala.Observer.onNext onNext]] and used in the next accumulator call. * @return * an Observable that emits the results of each call to the * accumulator function */ def scan[U >: T](accumulator: (U, U) => U): Observable[U] = { val func: Func2[_ >: U, _ >: U, _ <: U] = accumulator val func2 = func.asInstanceOf[Func2[T, T, T]] toScalaObservable[U](asJavaObservable.asInstanceOf[rx.Observable[T]].scan(func2)) } /** * Returns an Observable that emits a Boolean that indicates whether all of the items emitted by * the source Observable satisfy a condition. * * * * @param predicate * a function that evaluates an item and returns a Boolean * @return an Observable that emits `true` if all items emitted by the source * Observable satisfy the predicate; otherwise, `false` */ def forall(predicate: T => Boolean): Observable[Boolean] = { // type mismatch; found : rx.Observable[java.lang.Boolean] required: rx.Observable[_ <: scala.Boolean] // new Observable[Boolean](asJavaNotification.all(predicate)) // it's more fun in Scala: this.map(predicate).foldLeft(true)(_ && _) } /** * Returns an Observable that skips the first `num` items emitted by the source * Observable and emits the remainder. * * * * @param n * the number of items to skip * @return an Observable that is identical to the source Observable except that it does not * emit the first `num` items that the source emits */ def drop(n: Int): Observable[T] = { toScalaObservable[T](asJavaObservable.skip(n)) } /** * Returns an Observable that bypasses all items from the source Observable as long as the specified * condition holds true. Emits all further source items as soon as the condition becomes false. * * * * @param predicate * A function to test each item emitted from the source Observable for a condition. * @return an Observable that emits all items from the source Observable as soon as the condition * becomes false. */ def dropWhile(predicate: T => Boolean): Observable[T] = { toScalaObservable(asJavaObservable.skipWhile(predicate)) } /** * Returns an Observable that emits only the first `num` items emitted by the source * Observable. * * * * This method returns an Observable that will invoke a subscribing [[rx.lang.scala.Observer]]'s * [[rx.lang.scala.Observer.onNext onNext]] function a maximum of `num` times before invoking * [[rx.lang.scala.Observer.onCompleted onCompleted]]. * * @param n * the number of items to take * @return an Observable that emits only the first `num` items from the source * Observable, or all of the items from the source Observable if that Observable emits * fewer than `num` items */ def take(n: Int): Observable[T] = { toScalaObservable[T](asJavaObservable.take(n)) } /** * Returns an Observable that emits items emitted by the source Observable so long as a * specified condition is true. * * * * @param predicate * a function that evaluates an item emitted by the source Observable and returns a * Boolean * @return an Observable that emits the items from the source Observable so long as each item * satisfies the condition defined by `predicate` */ def takeWhile(predicate: T => Boolean): Observable[T] = { toScalaObservable[T](asJavaObservable.takeWhile(predicate)) } /** * Returns an Observable that emits only the last `count` items emitted by the source * Observable. * * * * @param count * the number of items to emit from the end of the sequence emitted by the source * Observable * @return an Observable that emits only the last `count` items emitted by the source * Observable */ def takeRight(count: Int): Observable[T] = { toScalaObservable[T](asJavaObservable.takeLast(count)) } /** * Returns an Observable that emits the items from the source Observable only until the * `other` Observable emits an item. * * * * @param that * the Observable whose first emitted item will cause `takeUntil` to stop * emitting items from the source Observable * @tparam E * the type of items emitted by `other` * @return an Observable that emits the items of the source Observable until such time as * `other` emits its first item */ def takeUntil[E](that: Observable[E]): Observable[T] = { toScalaObservable[T](asJavaObservable.takeUntil(that.asJavaObservable)) } /** * Returns an Observable that emits a single item, a list composed of all the items emitted by * the source Observable. * * * * Normally, an Observable that returns multiple items will do so by invoking its [[rx.lang.scala.Observer]]'s * [[rx.lang.scala.Observer.onNext onNext]] method for each such item. You can change * this behavior, instructing the Observable to compose a list of all of these items and then to * invoke the Observer's `onNext` function once, passing it the entire list, by * calling the Observable's `toList` method prior to calling its `Observable.subscribe` method. * * Be careful not to use this operator on Observables that emit infinite or very large numbers * of items, as you do not have the option to unsubscribe. * * @return an Observable that emits a single item: a List containing all of the items emitted by * the source Observable. */ def toSeq: Observable[Seq[T]] = { Observable.jObsOfListToScObsOfSeq(asJavaObservable.toList) : Observable[Seq[T]] // SI-7818 } /** * Groups the items emitted by this Observable according to a specified discriminator function. * * @param f * a function that extracts the key from an item * @tparam K * the type of keys returned by the discriminator function. * @return an Observable that emits `(key, observable)` pairs, where `observable` * contains all items for which `f` returned `key`. */ def groupBy[K](f: T => K): Observable[(K, Observable[T])] = { val o1 = asJavaObservable.groupBy[K](f) : rx.Observable[_ <: rx.observables.GroupedObservable[K, _ <: T]] val func = (o: rx.observables.GroupedObservable[K, _ <: T]) => (o.getKey, toScalaObservable[T](o)) toScalaObservable[(K, Observable[T])](o1.map[(K, Observable[T])](func)) } /** * Given an Observable that emits Observables, creates a single Observable that * emits the items emitted by the most recently published of those Observables. * * * * This operation is only available if `this` is of type `Observable[Observable[U]]` for some `U`, * otherwise you'll get a compilation error. * * @return an Observable that emits only the items emitted by the most recently published * Observable * * @usecase def switch[U]: Observable[U] * @inheritdoc */ def switch[U](implicit evidence: Observable[T] <:< Observable[Observable[U]]): Observable[U] = { val o2: Observable[Observable[U]] = this val o3: Observable[rx.Observable[_ <: U]] = o2.map(_.asJavaObservable) val o4: rx.Observable[_ <: rx.Observable[_ <: U]] = o3.asJavaObservable val o5 = rx.Observable.switchOnNext[U](o4) toScalaObservable[U](o5) } // Naming: We follow C# (switch), not Java (switchOnNext), because Java just had to avoid clash with keyword /** * Flattens two Observables into one Observable, without any transformation. * * * * You can combine items emitted by two Observables so that they act like a single * Observable by using the `merge` method. * * @param that * an Observable to be merged * @return an Observable that emits items from `this` and `that` until * `this` or `that` emits `onError` or `onComplete`. */ def merge[U >: T](that: Observable[U]): Observable[U] = { val thisJava: rx.Observable[_ <: U] = this.asJavaObservable val thatJava: rx.Observable[_ <: U] = that.asJavaObservable toScalaObservable[U](rx.Observable.merge(thisJava, thatJava)) } /** * This behaves like [[rx.lang.scala.Observable.merge]] except that if any of the merged Observables * notify of an error via [[rx.lang.scala.Observer.onError onError]], `mergeDelayError` will * refrain from propagating that error notification until all of the merged Observables have * finished emitting items. * * * * Even if multiple merged Observables send `onError` notifications, `mergeDelayError` will only invoke the `onError` method of its * Observers once. * * This method allows an Observer to receive all successfully emitted items from all of the * source Observables without being interrupted by an error notification from one of them. * * @param that * an Observable to be merged * @return an Observable that emits items that are the result of flattening the items emitted by * `this` and `that` */ def mergeDelayError[U >: T](that: Observable[U]): Observable[U] = { toScalaObservable[U](rx.Observable.mergeDelayError[U](this.asJavaObservable, that.asJavaObservable)) } /** * Flattens the sequence of Observables emitted by `this` 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 method. * * This operation is only available if `this` is of type `Observable[Observable[U]]` for some `U`, * otherwise you'll get a compilation error. * * @return an Observable that emits items that are the result of flattening the items emitted * by the Observables emitted by `this` * * @usecase def flatten[U]: Observable[U] * @inheritdoc */ def flatten[U](implicit evidence: Observable[T] <:< Observable[Observable[U]]): Observable[U] = { val o2: Observable[Observable[U]] = this val o3: Observable[rx.Observable[_ <: U]] = o2.map(_.asJavaObservable) val o4: rx.Observable[_ <: rx.Observable[_ <: U]] = o3.asJavaObservable val o5 = rx.Observable.merge[U](o4) toScalaObservable[U](o5) } /** * This behaves like `flatten` except that if any of the merged Observables * notify of an error via [[rx.lang.scala.Observer.onError onError]], this method will * refrain from propagating that error notification until all of the merged Observables have * finished emitting items. * * * * Even if multiple merged Observables send `onError` notifications, this method will only invoke the `onError` method of its * Observers once. * * This method allows an Observer to receive all successfully emitted items from all of the * source Observables without being interrupted by an error notification from one of them. * * This operation is only available if `this` is of type `Observable[Observable[U]]` for some `U`, * otherwise you'll get a compilation error. * * @return an Observable that emits items that are the result of flattening the items emitted by * the Observables emitted by the this Observable * * @usecase def flattenDelayError[U]: Observable[U] * @inheritdoc */ def flattenDelayError[U](implicit evidence: Observable[T] <:< Observable[Observable[U]]): Observable[U] = { val o2: Observable[Observable[U]] = this val o3: Observable[rx.Observable[_ <: U]] = o2.map(_.asJavaObservable) val o4: rx.Observable[_ <: rx.Observable[_ <: U]] = o3.asJavaObservable val o5 = rx.Observable.mergeDelayError[U](o4) toScalaObservable[U](o5) } /** * Combines two observables, emitting a pair of the latest values of each of * the source observables each time an event is received from one of the source observables, where the * aggregation is defined by the given function. * * @param that * The second source observable. * @return An Observable that combines the source Observables */ def combineLatest[U](that: Observable[U]): Observable[(T, U)] = { val f: Func2[_ >: T, _ >: U, _ <: (T, U)] = (t: T, u: U) => (t, u) toScalaObservable[(T, U)](rx.Observable.combineLatest[T, U, (T, U)](this.asJavaObservable, that.asJavaObservable, f)) } /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. * * NOTE: If events keep firing faster than the timeout then no data will be emitted. * * * * $debounceVsThrottle * * @param timeout * The time each value has to be 'the most recent' of the [[rx.lang.scala.Observable]] to ensure that it's not dropped. * * @return An [[rx.lang.scala.Observable]] which filters out values which are too quickly followed up with newer values. * @see `Observable.debounce` */ def throttleWithTimeout(timeout: Duration): Observable[T] = { toScalaObservable[T](asJavaObservable.throttleWithTimeout(timeout.length, timeout.unit)) } /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. * * NOTE: If events keep firing faster than the timeout then no data will be emitted. * * * * $debounceVsThrottle * * @param timeout * The time each value has to be 'the most recent' of the [[rx.lang.scala.Observable]] to ensure that it's not dropped. * * @return An [[rx.lang.scala.Observable]] which filters out values which are too quickly followed up with newer values. * @see `Observable.throttleWithTimeout` */ def debounce(timeout: Duration): Observable[T] = { toScalaObservable[T](asJavaObservable.debounce(timeout.length, timeout.unit)) } /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. * * NOTE: If events keep firing faster than the timeout then no data will be emitted. * * * * $debounceVsThrottle * * @param timeout * The time each value has to be 'the most recent' of the [[rx.lang.scala.Observable]] to ensure that it's not dropped. * @param scheduler * The [[rx.lang.scala.Scheduler]] to use internally to manage the timers which handle timeout for each event. * @return Observable which performs the throttle operation. * @see `Observable.throttleWithTimeout` */ def debounce(timeout: Duration, scheduler: Scheduler): Observable[T] = { toScalaObservable[T](asJavaObservable.debounce(timeout.length, timeout.unit, scheduler)) } /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. * * NOTE: If events keep firing faster than the timeout then no data will be emitted. * * * * @param timeout * The time each value has to be 'the most recent' of the [[rx.lang.scala.Observable]] to ensure that it's not dropped. * @param scheduler * The [[rx.lang.scala.Scheduler]] to use internally to manage the timers which handle timeout for each event. * @return Observable which performs the throttle operation. * @see `Observable.debounce` */ def throttleWithTimeout(timeout: Duration, scheduler: Scheduler): Observable[T] = { toScalaObservable[T](asJavaObservable.throttleWithTimeout(timeout.length, timeout.unit, scheduler)) } /** * Throttles by skipping value until `skipDuration` passes and then emits the next received value. * * This differs from `Observable.throttleLast` in that this only tracks passage of time whereas `Observable.throttleLast` ticks at scheduled intervals. * * * * @param skipDuration * Time to wait before sending another value after emitting last value. * @param scheduler * The [[rx.lang.scala.Scheduler]] to use internally to manage the timers which handle timeout for each event. * @return Observable which performs the throttle operation. */ def throttleFirst(skipDuration: Duration, scheduler: Scheduler): Observable[T] = { toScalaObservable[T](asJavaObservable.throttleFirst(skipDuration.length, skipDuration.unit, scheduler)) } /** * Throttles by skipping value until `skipDuration` passes and then emits the next received value. * * This differs from `Observable.throttleLast` in that this only tracks passage of time whereas `Observable.throttleLast` ticks at scheduled intervals. * * * * @param skipDuration * Time to wait before sending another value after emitting last value. * @return Observable which performs the throttle operation. */ def throttleFirst(skipDuration: Duration): Observable[T] = { toScalaObservable[T](asJavaObservable.throttleFirst(skipDuration.length, skipDuration.unit)) } /** * Throttles by returning the last value of each interval defined by 'intervalDuration'. * * This differs from `Observable.throttleFirst` in that this ticks along at a scheduled interval whereas `Observable.throttleFirst` does not tick, it just tracks passage of time. * * * * @param intervalDuration * Duration of windows within with the last value will be chosen. * @return Observable which performs the throttle operation. */ def throttleLast(intervalDuration: Duration): Observable[T] = { toScalaObservable[T](asJavaObservable.throttleLast(intervalDuration.length, intervalDuration.unit)) } /** * Throttles by returning the last value of each interval defined by 'intervalDuration'. * * This differs from `Observable.throttleFirst` in that this ticks along at a scheduled interval whereas `Observable.throttleFirst` does not tick, it just tracks passage of time. * * * * @param intervalDuration * Duration of windows within with the last value will be chosen. * @return Observable which performs the throttle operation. */ def throttleLast(intervalDuration: Duration, scheduler: Scheduler): Observable[T] = { toScalaObservable[T](asJavaObservable.throttleLast(intervalDuration.length, intervalDuration.unit, scheduler)) } /** * Returns an Observable that sums up the elements of this Observable. * * This operation is only available if the elements of this Observable are numbers, otherwise * you will get a compilation error. * * @return an Observable emitting the sum of all the elements of the source Observable * as its single item. * * @usecase def sum: Observable[T] * @inheritdoc */ def sum[U >: T](implicit num: Numeric[U]): Observable[U] = { foldLeft(num.zero)(num.plus) } /** * Returns an Observable that multiplies up the elements of this Observable. * * This operation is only available if the elements of this Observable are numbers, otherwise * you will get a compilation error. * * @return an Observable emitting the product of all the elements of the source Observable * as its single item. * * @usecase def product: Observable[T] * @inheritdoc */ def product[U >: T](implicit num: Numeric[U]): Observable[U] = { foldLeft(num.one)(num.times) } /** * Returns an Observable that emits only the very first item emitted by the source Observable, or * a default value if the source Observable is empty. * * * * @param default * The default value to emit if the source Observable doesn't emit anything. * This is a by-name parameter, so it is only evaluated if the source Observable doesn't emit anything. * @return an Observable that emits only the very first item from the source, or a default value * if the source Observable completes without emitting any item. */ def firstOrElse[U >: T](default: => U): Observable[U] = { this.take(1).foldLeft[Option[U]](None)((v: Option[U], e: U) => Some(e)).map({ case Some(element) => element case None => default }) } /** * Returns an Observable that emits only the very first item emitted by the source Observable, or * a default value if the source Observable is empty. * * * * @param default * The default value to emit if the source Observable doesn't emit anything. * This is a by-name parameter, so it is only evaluated if the source Observable doesn't emit anything. * @return an Observable that emits only the very first item from the source, or a default value * if the source Observable completes without emitting any item. */ def headOrElse[U >: T](default: => U): Observable[U] = firstOrElse(default) /** * Returns an Observable that emits only the very first item emitted by the source Observable. * This is just a shorthand for `take(1)`. * * * * @return an Observable that emits only the very first item from the source, or none if the * source Observable completes without emitting a single item. */ def first: Observable[T] = take(1) /* TODO once https://github.com/Netflix/RxJava/issues/417 is fixed, we can add head and tail methods /** * emits NoSuchElementException("head of empty Observable") if empty */ def head: Observable[T] = { this.take(1).fold[Option[T]](None)((v: Option[T], e: T) => Some(e)).map({ case Some(element) => element case None => throw new NoSuchElementException("head of empty Observable") }) } /** * emits an UnsupportedOperationException("tail of empty list") if empty */ def tail: Observable[T] = ??? */ /** * Returns an Observable that forwards all sequentially distinct items emitted from the source Observable. * * * * @return an Observable of sequentially distinct items */ def distinctUntilChanged: Observable[T] = { toScalaObservable[T](asJavaObservable.distinctUntilChanged) } /** * Returns an Observable that forwards all items emitted from the source Observable that are sequentially * distinct according to a key selector function. * * * * @param keySelector * a function that projects an emitted item to a key value which is used for deciding whether an item is sequentially * distinct from another one or not * @return an Observable of sequentially distinct items */ def distinctUntilChanged[U](keySelector: T => U): Observable[T] = { toScalaObservable[T](asJavaObservable.distinctUntilChanged[U](keySelector)) } /** * Returns an Observable that forwards all distinct items emitted from the source Observable. * * * * @return an Observable of distinct items */ def distinct: Observable[T] = { toScalaObservable[T](asJavaObservable.distinct()) } /** * Returns an Observable that forwards all items emitted from the source Observable that are distinct according * to a key selector function. * * * * @param keySelector * a function that projects an emitted item to a key value which is used for deciding whether an item is * distinct from another one or not * @return an Observable of distinct items */ def distinct[U](keySelector: T => U): Observable[T] = { toScalaObservable[T](asJavaObservable.distinct[U](keySelector)) } /** * Returns an Observable that counts the total number of elements in the source Observable. * * * * @return an Observable emitting the number of counted elements of the source Observable * as its single item. */ def length: Observable[Int] = { toScalaObservable[Integer](asJavaObservable.count()).map(_.intValue()) } /** * Returns an Observable that counts the total number of elements in the source Observable. * * * * @return an Observable emitting the number of counted elements of the source Observable * as its single item. */ def size: Observable[Int] = length /** * Retry subscription to origin Observable upto given retry count. * * * * If [[rx.lang.scala.Observer.onError]] is invoked the source Observable will be re-subscribed to as many times as defined by retryCount. * * Any [[rx.lang.scala.Observer.onNext]] calls received on each attempt will be emitted and concatenated together. * * For example, if an Observable fails on first time but emits [1, 2] then succeeds the second time and * emits [1, 2, 3, 4, 5] then the complete output would be [1, 2, 1, 2, 3, 4, 5, onCompleted]. * * @param retryCount * Number of retry attempts before failing. * @return Observable with retry logic. */ def retry(retryCount: Int): Observable[T] = { toScalaObservable[T](asJavaObservable.retry(retryCount)) } /** * Retry subscription to origin Observable whenever onError is called (infinite retry count). * * * * If [[rx.lang.scala.Observer.onError]] is invoked the source Observable will be re-subscribed to. * * Any [[rx.lang.scala.Observer.onNext]] calls received on each attempt will be emitted and concatenated together. * * For example, if an Observable fails on first time but emits [1, 2] then succeeds the second time and * emits [1, 2, 3, 4, 5] then the complete output would be [1, 2, 1, 2, 3, 4, 5, onCompleted]. * @return Observable with retry logic. */ def retry: Observable[T] = { toScalaObservable[T](asJavaObservable.retry()) } /** * Converts an Observable into a [[rx.lang.scala.observables.BlockingObservable]] (an Observable with blocking * operators). * * @see Blocking Observable Operators */ def toBlockingObservable: BlockingObservable[T] = { new BlockingObservable[T](asJavaObservable.toBlockingObservable) } /** * Perform work in parallel by sharding an `Observable[T]` on a * [[rx.lang.scala.concurrency.Schedulers.threadPoolForComputation computation]] * [[rx.lang.scala.Scheduler]] and return an `Observable[R]` with the output. * * @param f * a function that applies Observable operators to `Observable[T]` in parallel and returns an `Observable[R]` * @return an Observable with the output of the function executed on a [[rx.lang.scala.Scheduler]] */ def parallel[R](f: Observable[T] => Observable[R]): Observable[R] = { val fJava: Func1[rx.Observable[T], rx.Observable[R]] = (jo: rx.Observable[T]) => f(toScalaObservable[T](jo)).asJavaObservable.asInstanceOf[rx.Observable[R]] toScalaObservable(asJavaObservable.asInstanceOf[rx.Observable[T]].parallel[R](fJava)) } /** * Perform work in parallel by sharding an `Observable[T]` on a [[rx.lang.scala.Scheduler]] and return an `Observable[R]` with the output. * * @param f * a function that applies Observable operators to `Observable[T]` in parallel and returns an `Observable[R]` * @param scheduler * a [[rx.lang.scala.Scheduler]] to perform the work on. * @return an Observable with the output of the function executed on a [[rx.lang.scala.Scheduler]] */ def parallel[R](f: Observable[T] => Observable[R], scheduler: Scheduler): Observable[R] = { val fJava: Func1[rx.Observable[T], rx.Observable[R]] = (jo: rx.Observable[T]) => f(toScalaObservable[T](jo)).asJavaObservable.asInstanceOf[rx.Observable[R]] toScalaObservable(asJavaObservable.asInstanceOf[rx.Observable[T]].parallel[R](fJava, scheduler)) } /** Tests whether a predicate holds for some of the elements of this `Observable`. * * @param p the predicate used to test elements. * @return an Observable emitting one single Boolean, which is `true` if the given predicate `p` * holds for some of the elements of this Observable, and `false` otherwise. */ def exists(p: T => Boolean): Observable[Boolean] = { toScalaObservable[java.lang.Boolean](asJavaObservable.exists(p)).map(_.booleanValue()) } /** Tests whether this `Observable` emits no elements. * * @return an Observable emitting one single Boolean, which is `true` if this `Observable` * emits no elements, and `false` otherwise. */ def isEmpty: Observable[Boolean] = { toScalaObservable[java.lang.Boolean](asJavaObservable.isEmpty()).map(_.booleanValue()) } def withFilter(p: T => Boolean): WithFilter[T] = { new WithFilter[T](p, asJavaObservable) } /** * Returns an Observable that applies the given function to each item emitted by an * Observable. * * @param observer the observer * * @return an Observable with the side-effecting behavior applied. */ def doOnEach(observer: Observer[T]): Observable[T] = { toScalaObservable[T](asJavaObservable.doOnEach(observer.asJavaObserver)) } /** * Invokes an action when the source Observable calls onNext. * * @param onNext the action to invoke when the source Observable calls onNext * @return the source Observable with the side-effecting behavior applied */ def doOnNext(onNext: T => Unit): Observable[T] = { toScalaObservable[T](asJavaObservable.doOnNext(onNext)) } /** * Invokes an action if the source Observable calls onError. * * @param onError the action to invoke if the source Observable calls * onError * @return the source Observable with the side-effecting behavior applied */ def doOnError(onError: Throwable => Unit): Observable[T] = { toScalaObservable[T](asJavaObservable.doOnError(onError)) } /** * Invokes an action when the source Observable calls onCompleted. * * @param onCompleted the action to invoke when the source Observable calls * onCompleted * @return the source Observable with the side-effecting behavior applied */ def doOnCompleted(onCompleted: () => Unit): Observable[T] = { toScalaObservable[T](asJavaObservable.doOnCompleted(onCompleted)) } /** * Returns an Observable that applies the given function to each item emitted by an * Observable. * * @param onNext this function will be called whenever the Observable emits an item * * @return an Observable with the side-effecting behavior applied. */ def doOnEach(onNext: T => Unit): Observable[T] = { toScalaObservable[T](asJavaObservable.doOnNext(onNext)) } /** * Returns an Observable that applies the given function to each item emitted by an * Observable. * * @param onNext this function will be called whenever the Observable emits an item * @param onError this function will be called if an error occurs * * @return an Observable with the side-effecting behavior applied. */ def doOnEach(onNext: T => Unit, onError: Throwable => Unit): Observable[T] = { toScalaObservable[T](asJavaObservable.doOnEach(Observer(onNext, onError, ()=>{}))) } /** * Returns an Observable that applies the given function to each item emitted by an * Observable. * * @param onNext this function will be called whenever the Observable emits an item * @param onError this function will be called if an error occurs * @param onCompleted the action to invoke when the source Observable calls * * @return an Observable with the side-effecting behavior applied. */ def doOnEach(onNext: T => Unit, onError: Throwable => Unit, onCompleted: () => Unit): Observable[T] = { toScalaObservable[T](asJavaObservable.doOnEach(Observer(onNext, onError,onCompleted))) } } /** * Provides various ways to construct new Observables. */ object Observable { import scala.collection.JavaConverters._ import scala.collection.immutable.Range import scala.concurrent.duration.Duration import scala.concurrent.{Future, ExecutionContext} import scala.util.{Success, Failure} import ImplicitFunctionConversions._ import JavaConversions._ import rx.lang.scala.subjects.AsyncSubject private[scala] def jObsOfListToScObsOfSeq[T](jObs: rx.Observable[_ <: java.util.List[T]]): Observable[Seq[T]] = { val oScala1: Observable[java.util.List[T]] = new Observable[java.util.List[T]]{ val asJavaObservable = jObs } oScala1.map((lJava: java.util.List[T]) => lJava.asScala) } private[scala] def jObsOfJObsToScObsOfScObs[T](jObs: rx.Observable[_ <: rx.Observable[_ <: T]]): Observable[Observable[T]] = { val oScala1: Observable[rx.Observable[_ <: T]] = new Observable[rx.Observable[_ <: T]]{ val asJavaObservable = jObs } oScala1.map((oJava: rx.Observable[_ <: T]) => oJava) } /** * Creates an Observable that will execute the given function when an [[rx.lang.scala.Observer]] subscribes to it. * * * * Write the function you pass to `create` so that it behaves as an Observable: It * should invoke the Observer's [[rx.lang.scala.Observer.onNext onNext]], [[rx.lang.scala.Observer.onError onError]], and [[rx.lang.scala.Observer.onCompleted onCompleted]] methods * appropriately. * * A well-formed Observable must invoke either the Observer's `onCompleted` method * exactly once or its `onError` method exactly once. * * See Rx Design Guidelines (PDF) * for detailed information. * * * @tparam T * the type of the items that this Observable emits. * @param func * a function that accepts an `Observer[T]`, invokes its `onNext`, `onError`, and `onCompleted` methods * as appropriate, and returns a [[rx.lang.scala.Subscription]] to allow the Observer to * canceling the subscription. * @return * an Observable that, when an [[rx.lang.scala.Observer]] subscribes to it, will execute the given function. */ def create[T](func: Observer[T] => Subscription): Observable[T] = { toScalaObservable[T](rx.Observable.create(new OnSubscribeFunc[T] { def onSubscribe(t1: rx.Observer[_ >: T]): rx.Subscription = { func(Observer(t1)) } })) } /** * Returns an Observable that invokes an [[rx.lang.scala.Observer]]'s [[rx.lang.scala.Observer.onError onError]] * method when the Observer subscribes to it. * * * * @param exception * the particular error to report * @tparam T * the type of the items (ostensibly) emitted by the Observable * @return an Observable that invokes the [[rx.lang.scala.Observer]]'s [[rx.lang.scala.Observer.onError onError]] * method when the Observer subscribes to it */ def error[T](exception: Throwable): Observable[T] = { toScalaObservable[T](rx.Observable.error(exception)) } /** * Returns an Observable that emits no data to the [[rx.lang.scala.Observer]] and * immediately invokes its [[rx.lang.scala.Observer#onCompleted onCompleted]] method * with the specified scheduler. *

* * * @param scheduler the scheduler to call the [[rx.lang.scala.Observer#onCompleted onCompleted]] method * @param T the type of the items (ostensibly) emitted by the Observable * @return an Observable that returns no data to the [[rx.lang.scala.Observer]] and * immediately invokes the [[rx.lang.scala.Observer]]r's * [[rx.lang.scala.Observer#onCompleted onCompleted]] method with the * specified scheduler * @see RxJava Wiki: empty() * @see MSDN: Observable.Empty Method (IScheduler) */ def empty[T]: Observable[T] = { toScalaObservable(rx.Observable.empty[T]()) } /** * Returns an Observable that emits no data to the [[rx.lang.scala.Observer]] and * immediately invokes its [[rx.lang.scala.Observer#onCompleted onCompleted]] method * with the specified scheduler. *

* * * @param scheduler the scheduler to call the [[rx.lang.scala.Observer#onCompleted onCompleted]] method * @param T the type of the items (ostensibly) emitted by the Observable * @return an Observable that returns no data to the [[rx.lang.scala.Observer]] and * immediately invokes the [[rx.lang.scala.Observer]]r's * [[rx.lang.scala.Observer#onCompleted onCompleted]] method with the * specified scheduler * @see RxJava Wiki: empty() * @see MSDN: Observable.Empty Method (IScheduler) */ def empty[T](scheduler: Scheduler): Observable[T] = { toScalaObservable(rx.Observable.empty[T](scalaSchedulerToJavaScheduler(scheduler))) } /** * Converts a sequence of values into an Observable. * * * * Implementation note: the entire array will be immediately emitted each time an [[rx.lang.scala.Observer]] subscribes. * Since this occurs before the [[rx.lang.scala.Subscription]] is returned, * it in not possible to unsubscribe from the sequence before it completes. * * @param items * the source Array * @tparam T * the type of items in the Array, and the type of items to be emitted by the * resulting Observable * @return an Observable that emits each item in the source Array */ def items[T](items: T*): Observable[T] = { toScalaObservable[T](rx.Observable.from(items.toIterable.asJava)) } /** Returns an Observable emitting the value produced by the Future as its single item. * If the future fails, the Observable will fail as well. * * @param f Future whose value ends up in the resulting Observable * @return an Observable completed after producing the value of the future, or with an exception */ def from[T](f: Future[T])(implicit execContext: ExecutionContext): Observable[T] = { val s = AsyncSubject[T]() f.onComplete { case Failure(e) => s.onError(e) case Success(c) => s.onNext(c) s.onCompleted() } s } /** * Converts an `Iterable` into an Observable. * * * * Note: the entire iterable sequence is immediately emitted each time an * Observer subscribes. Since this occurs before the * `Subscription` is returned, it is not possible to unsubscribe from * the sequence before it completes. * * @param iterable the source `Iterable` sequence * @param T the type of items in the `Iterable` sequence and the * type of items to be emitted by the resulting Observable * @return an Observable that emits each item in the source `Iterable` * sequence */ def from[T](iterable: Iterable[T]): Observable[T] = { toScalaObservable(rx.Observable.from(iterable.asJava)) } /** * * @param iterable the source `Iterable` sequence * @param scheduler the scheduler to use * @tparam T the type of items in the `Iterable` sequence and the * type of items to be emitted by the resulting Observable * @return an Observable that emits each item in the source `Iterable` * sequence */ def from[T](iterable: Iterable[T], scheduler: Scheduler): Observable[T] = { toScalaObservable(rx.Observable.from(iterable.asJava, scheduler.asJavaScheduler)) } /** * Returns an Observable that calls an Observable factory to create its Observable for each * new Observer that subscribes. That is, for each subscriber, the actual Observable is determined * by the factory function. * * * * The defer operator allows you to defer or delay emitting items from an Observable until such * time as an Observer subscribes to the Observable. This allows an [[rx.lang.scala.Observer]] to easily * obtain updates or a refreshed version of the sequence. * * @param observable * the Observable factory function to invoke for each [[rx.lang.scala.Observer]] that * subscribes to the resulting Observable * @tparam T * the type of the items emitted by the Observable * @return an Observable whose [[rx.lang.scala.Observer]]s trigger an invocation of the given Observable * factory function */ def defer[T](observable: => Observable[T]): Observable[T] = { toScalaObservable[T](rx.Observable.defer[T](() => observable.asJavaObservable)) } /** * Returns an Observable that never sends any items or notifications to an [[rx.lang.scala.Observer]]. * * * * This Observable is useful primarily for testing purposes. * * @return an Observable that never sends any items or notifications to an [[rx.lang.scala.Observer]] */ def never: Observable[Nothing] = { toScalaObservable[Nothing](rx.Observable.never()) } /** * Given 3 observables, returns an observable that emits Tuples of 3 elements each. * The first emitted Tuple will contain the first element of each source observable, * the second Tuple the second element of each source observable, and so on. * * @return an Observable that emits the zipped Observables */ def zip[A, B, C](obA: Observable[A], obB: Observable[B], obC: Observable[C]): Observable[(A, B, C)] = { toScalaObservable[(A, B, C)](rx.Observable.zip[A, B, C, (A, B, C)](obA.asJavaObservable, obB.asJavaObservable, obC.asJavaObservable, (a: A, b: B, c: C) => (a, b, c))) } /** * Given 4 observables, returns an observable that emits Tuples of 4 elements each. * The first emitted Tuple will contain the first element of each source observable, * the second Tuple the second element of each source observable, and so on. * * @return an Observable that emits the zipped Observables */ def zip[A, B, C, D](obA: Observable[A], obB: Observable[B], obC: Observable[C], obD: Observable[D]): Observable[(A, B, C, D)] = { toScalaObservable[(A, B, C, D)](rx.Observable.zip[A, B, C, D, (A, B, C, D)](obA.asJavaObservable, obB.asJavaObservable, obC.asJavaObservable, obD.asJavaObservable, (a: A, b: B, c: C, d: D) => (a, b, c, d))) } /** * Given an Observable emitting `N` source observables, returns an observable that * emits Seqs of `N` elements each. * The first emitted Seq will contain the first element of each source observable, * the second Seq the second element of each source observable, and so on. * * Note that the returned Observable will only start emitting items once the given * `Observable[Observable[T]]` has completed, because otherwise it cannot know `N`. * * @param observables * An Observable emitting N source Observables * @return an Observable that emits the zipped Seqs */ def zip[T](observables: Observable[Observable[T]]): Observable[Seq[T]] = { val f: FuncN[Seq[T]] = (args: Seq[java.lang.Object]) => { val asSeq: Seq[Object] = args.toSeq asSeq.asInstanceOf[Seq[T]] } val list = observables.map(_.asJavaObservable).asJavaObservable val o = rx.Observable.zip(list, f) toScalaObservable[Seq[T]](o) } /** * Emits `0`, `1`, `2`, `...` with a delay of `duration` between consecutive numbers. * * * * @param duration * duration between two consecutive numbers * @return An Observable that emits a number each time interval. */ def interval(duration: Duration): Observable[Long] = { toScalaObservable[java.lang.Long](rx.Observable.interval(duration.length, duration.unit)).map(_.longValue()) /*XXX*/ } /** * Emits `0`, `1`, `2`, `...` with a delay of `duration` between consecutive numbers. * * * * @param duration * duration between two consecutive numbers * @param scheduler * the scheduler to use * @return An Observable that emits a number each time interval. */ def interval(duration: Duration, scheduler: Scheduler): Observable[Long] = { toScalaObservable[java.lang.Long](rx.Observable.interval(duration.length, duration.unit, scheduler)).map(_.longValue()) /*XXX*/ } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy