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

monifu.reactive.Observer.scala Maven / Gradle / Ivy

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

package monifu.reactive

import monifu.concurrent.Scheduler
import monifu.reactive.Ack.{Cancel, Continue}
import monifu.reactive.observers.{SynchronousObserver, SynchronousSubscriber}
import monifu.reactive.streams._
import org.reactivestreams.{Subscriber => RSubscriber}
import scala.annotation.tailrec
import scala.concurrent.{Future, Promise}
import scala.util.control.NonFatal


/**
 * The Observer from the Rx pattern is the trio of callbacks that
 * get subscribed to an Observable for receiving events.
 *
 * The events received must follow the Rx grammar, which is:
 *      onNext *   (onComplete | onError)?
 *
 * That means an Observer can receive zero or multiple events, the stream
 * ending either in one or zero `onComplete` or `onError` (just one, not both),
 * and after onComplete or onError, a well behaved Observable implementation
 * shouldn't send any more onNext events.
 */
trait Observer[-T] {
  def onNext(elem: T): Future[Ack]

  def onError(ex: Throwable): Unit

  def onComplete(): Unit
}

object Observer {
  /**
   * Given an `org.reactivestreams.Subscriber` as defined by the
   * [[http://www.reactive-streams.org/ Reactive Streams]] specification,
   * it builds an [[Observer]] instance compliant with the
   * Monifu Rx implementation.
   */
  def fromReactiveSubscriber[T](subscriber: RSubscriber[T])(implicit s: Scheduler): Subscriber[T] = {
    ReactiveSubscriberAsMonifuSubscriber(subscriber)
  }

  /**
   * Transforms the source [[Observer]] into a `org.reactivestreams.Subscriber`
   * instance as defined by the [[http://www.reactive-streams.org/ Reactive Streams]]
   * specification.
   */
  def toReactiveSubscriber[T](observer: Observer[T])(implicit s: Scheduler): RSubscriber[T] = {
    toReactiveSubscriber(observer, s.env.batchSize)(s)
  }

  /**
   * Transforms the source [[Observer]] into a `org.reactivestreams.Subscriber`
   * instance as defined by the [[http://www.reactive-streams.org/ Reactive Streams]]
   * specification.
   *
   * @param bufferSize a strictly positive number, representing the size
   *                   of the buffer used and the number of elements requested
   *                   on each cycle when communicating demand, compliant with
   *                   the reactive streams specification
   */
  def toReactiveSubscriber[T](observer: Observer[T], bufferSize: Int)(implicit s: Scheduler): RSubscriber[T] = {
    require(bufferSize > 0, "requestCount > 0")
    observer match {
      case sync: SynchronousObserver[_] =>
        val inst = sync.asInstanceOf[SynchronousObserver[T]]
        SynchronousSubscriberAsReactiveSubscriber(SynchronousSubscriber(inst, s), bufferSize)
      case async =>
        SubscriberAsReactiveSubscriber(Subscriber(async, s), bufferSize)
    }
  }

  /**
   * Feeds the given [[Observer]] instance with elements from the given iterable,
   * respecting the contract and returning a `Future[Ack]` with the last
   * acknowledgement given after the last emitted element.
   */
  def feed[T](source: Observer[T], iterable: Iterable[T])(implicit s: Scheduler): Future[Ack] = {
    try feed(source, iterable.iterator) catch {
      case NonFatal(ex) =>
        source.onError(ex)
        Cancel
    }
  }

  /**
   * Feeds the given [[Observer]] instance with elements from the given iterator,
   * respecting the contract and returning a `Future[Ack]` with the last
   * acknowledgement given after the last emitted element.
   */
  def feed[T](source: Observer[T], iterator: Iterator[T])(implicit s: Scheduler): Future[Ack] = {
    def scheduleFeedLoop(promise: Promise[Ack], iterator: Iterator[T]): Future[Ack] = {
      s.execute(new Runnable {
        private[this] val modulus = s.env.batchSize - 1

        @tailrec
        def fastLoop(syncIndex: Int): Unit = {
          val ack = source.onNext(iterator.next())

          if (iterator.hasNext) {
            val nextIndex = if (!ack.isCompleted) 0 else
              (syncIndex + 1) & modulus

            if (nextIndex != 0) {
              if (ack == Continue || ack.value.get == Continue.IsSuccess)
                fastLoop(nextIndex)
              else
                promise.complete(ack.value.get)
            }
            else ack.onComplete {
              case Continue.IsSuccess =>
                run()
              case other =>
                promise.complete(other)
            }
          }
          else {
            promise.completeWith(ack)
          }
        }

        def run(): Unit = {
          try fastLoop(0) catch {
            case NonFatal(ex) =>
              try source.onError(ex) finally {
                promise.failure(ex)
              }
          }
        }
      })

      promise.future
    }

    try {
      if (iterator.hasNext)
        scheduleFeedLoop(Promise[Ack](), iterator)
      else
        Continue
    }
    catch {
      case NonFatal(ex) =>
        source.onError(ex)
        Cancel
    }
  }

  /**
   * Extension methods for [[Observer]].
   */
  implicit class Extensions[T](val source: Observer[T]) extends AnyVal {
    /**
     * Transforms the source [[Observer]] into a `org.reactivestreams.Subscriber`
     * instance as defined by the [[http://www.reactive-streams.org/ Reactive Streams]]
     * specification.
     */
    def toReactive(implicit s: Scheduler): RSubscriber[T] =
      Observer.toReactiveSubscriber(source)

    /**
     * Transforms the source [[Observer]] into a `org.reactivestreams.Subscriber`
     * instance as defined by the [[http://www.reactive-streams.org/ Reactive Streams]]
     * specification.
     *
     * @param bufferSize a strictly positive number, representing the size
     *                   of the buffer used and the number of elements requested
     *                   on each cycle when communicating demand, compliant with
     *                   the reactive streams specification
     */
    def toReactive(bufferSize: Int)(implicit s: Scheduler): RSubscriber[T] =
      Observer.toReactiveSubscriber(source, bufferSize)

    /**
     * Feeds the source [[Observer]] with elements from the given iterable,
     * respecting the contract and returning a `Future[Ack]` with the last
     * acknowledgement given after the last emitted element.
     */
    def feed(iterable: Iterable[T])(implicit s: Scheduler): Future[Ack] =
      Observer.feed(source, iterable)

    /**
     * Feeds the source [[Observer]] with elements from the given iterator,
     * respecting the contract and returning a `Future[Ack]` with the last
     * acknowledgement given after the last emitted element.
     */
    def feed(iterator: Iterator[T])(implicit s: Scheduler): Future[Ack] =
      Observer.feed(source, iterator)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy