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

com.sandinh.rx.Implicits.scala Maven / Gradle / Ivy

package com.sandinh.rx

import rx.functions.{Func2, Func1}
import rx.{Observer, Observable}
import scala.concurrent.{Future, Promise}
import scala.language.implicitConversions

object Implicits {
  private final class FutureObserver[T](p: Promise[T]) extends Observer[T] {
    def onCompleted(): Unit = {}
    def onNext(t: T): Unit = p success t
    def onError(e: Throwable): Unit = p failure e
  }

  private final class SFunc1[T1, R](f: T1 => R) extends Func1[T1, R] {
    def call(t1: T1): R = f(t1)
  }
  private final class SFunc2[T1, T2, R](f: (T1, T2) => R)
      extends Func2[T1, T2, R] {
    def call(t1: T1, t2: T2): R = f(t1, t2)
  }

  implicit class ScalaObservable[T](val underlying: Observable[T])
      extends AnyVal {

    /** @note if `underlying`:
      * + is empty then `toFuture` will fail with NoSuchElementException("Sequence contains no elements")
      * + emit more than one values then `toFuture` will fail with IllegalArgumentException("Sequence contains too many elements")
      */
    def toFuture: Future[T] = {
      val p = Promise[T]()
      underlying.single.subscribe(new FutureObserver(p))
      p.future
    }

    /** scala map. We can't name `map` because scala compiler will not implicitly pick this method */
    @inline def scMap[R](f: T => R): Observable[R] =
      underlying.map[R](new SFunc1(f))

    /** scala flatMap. We can't name `flatMap` because scala compiler will not implicitly pick this method.
      * @note result may "out of order". If need in-order then you should use scConcatMap
      */
    @inline def scFlatMap[R](f: T => Observable[R]): Observable[R] =
      underlying.flatMap[R](new SFunc1(f))

    /** scala concatMap. We can't name `concatMap` because scala compiler will not implicitly pick this method.
      * @note If don't need in-order then you should use scFlatMap
      */
    @inline def scConcatMap[R](f: T => Observable[R]): Observable[R] =
      underlying.concatMap[R](new SFunc1(f))

    /** we not named `foldLeft` to indicate that Observable may emit items "out of order" (not like Future)
      * Ex: Observable.from(2, 1).flatMap(Observable.timer(_ seconds)).fold("")(_ + _)
      * is Observable of "12" (not "21")
      * @note result may "out of order"
      */
    @inline def fold[R](z: R)(op: (R, T) => R): Observable[R] =
      underlying.reduce(z, new SFunc2(op))
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy