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

monix.execution.CancelableFuture.scala Maven / Gradle / Ivy

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

package monix.execution

import monix.execution.Cancelable.IsDummy
import monix.execution.CancelableFuture.{Async, Never, Pure}
import monix.execution.cancelables.{ChainedCancelable, SingleAssignCancelable}
import monix.execution.schedulers.TrampolinedRunnable
import monix.execution.schedulers.TrampolineExecutionContext.immediate

import scala.concurrent._
import scala.concurrent.duration.Duration
import scala.reflect.ClassTag
import scala.util.{Failure, Success, Try}
import scala.util.control.NonFatal

/** Represents an asynchronous computation that can be canceled
  * as long as it isn't complete.
  */
sealed abstract class CancelableFuture[+A] extends Future[A] with Cancelable { self =>
  /** Returns this future's underlying [[Cancelable]] reference. */
  private[monix] def cancelable: Cancelable

  /** Returns the underlying `Future` reference. */
  private[monix] def underlying: Future[A]

  override final def failed: CancelableFuture[Throwable] = {
    implicit val ec = immediate
    transformWith {
      case Success(_) =>
        CancelableFuture.failed(new NoSuchElementException("failed"))
      case Failure(e) =>
        CancelableFuture.successful(e)
    }
  }

  override final def transform[S](s: (A) => S, f: (Throwable) => Throwable)(
    implicit executor: ExecutionContext): CancelableFuture[S] =
    transform {
      case Success(a) => Success(s(a))
      case Failure(e) => Failure(f(e))
    }

  override final def map[S](f: (A) => S)(implicit executor: ExecutionContext): CancelableFuture[S] =
    transform {
      case Success(a) => Success(f(a))
      case fail => fail.asInstanceOf[Try[S]]
    }

  override final def filter(p: (A) => Boolean)(implicit executor: ExecutionContext): CancelableFuture[A] =
    transform {
      case Success(a) if !p(a) =>
        throw new NoSuchElementException("Future.filter predicate is not satisfied")
      case pass =>
        pass
    }

  override final def collect[S](pf: PartialFunction[A, S])(implicit executor: ExecutionContext): CancelableFuture[S] =
    transform {
      case Success(a) =>
        if (pf.isDefinedAt(a)) Success(pf(a))
        else
          throw new NoSuchElementException("Future.collect partial function is not defined at: " + a)
      case fail @ Failure(_) =>
        fail.asInstanceOf[Failure[S]]
    }

  override final def recover[U >: A](pf: PartialFunction[Throwable, U])(
    implicit executor: ExecutionContext): CancelableFuture[U] =
    transform {
      case ref @ Success(_) => ref
      case Failure(e) =>
        if (!pf.isDefinedAt(e)) throw e
        Success(pf(e))
    }

  override final def recoverWith[U >: A](pf: PartialFunction[Throwable, Future[U]])(
    implicit executor: ExecutionContext): CancelableFuture[U] =
    transformWith {
      case Success(_) => this
      case Failure(e) =>
        if (!pf.isDefinedAt(e)) this
        else pf(e)
    }

  override final def zip[U](that: Future[U]): CancelableFuture[(A, U)] = {
    implicit val ec = immediate
    for (a <- this; b <- that) yield (a, b)
  }

  override final def fallbackTo[U >: A](that: Future[U]): CancelableFuture[U] = {
    implicit val ec = immediate
    transformWith {
      case Success(_) => this
      case Failure(_) => that
    }
  }

  override final def mapTo[S](implicit tag: ClassTag[S]): CancelableFuture[S] = {
    this match {
      case Async(other, cRef) =>
        CancelableFuture(other.mapTo[S], cRef)
      case _: Pure[_] =>
        CancelableFuture(super.mapTo[S], Cancelable.empty)
      case Never =>
        Never
    }
  }

  override final def andThen[U](pf: PartialFunction[Try[A], U])(
    implicit executor: ExecutionContext): CancelableFuture[A] =
    transformWith { r =>
      if (pf.isDefinedAt(r)) pf(r)
      this
    }

  override final def flatMap[S](f: (A) => Future[S])(implicit executor: ExecutionContext): CancelableFuture[S] =
    transformWith {
      case Success(s) => f(s)
      case Failure(_) => this.asInstanceOf[CancelableFuture[S]]
    }

  def transform[S](f: Try[A] => Try[S])(implicit executor: ExecutionContext): CancelableFuture[S] = {
    val next = FutureUtils.transform(underlying, f)
    CancelableFuture(next, cancelable)
  }

  def transformWith[S](f: Try[A] => Future[S])(implicit executor: ExecutionContext): CancelableFuture[S] = {
    // Cancelable reference that needs to be chained with other
    // cancelable references created in the loop
    val cRef = ChainedCancelable(cancelable)

    // FutureUtils will use a polyfill for Scala 2.11 and will
    // use the real `transformWith` on Scala 2.12
    val f2 = FutureUtils.transformWith(
      underlying, { result: Try[A] =>
        val nextRef: Future[S] =
          try f(result)
          catch { case e if NonFatal(e) => Future.failed(e) }

        // Checking to see if we are dealing with a "flatMap"
        // future, in which case we need to chain the cancelable
        // reference in order to not create a memory leak
        nextRef match {
          case ref: CancelableFuture[_] if ref ne Never =>
            val cf = ref.asInstanceOf[CancelableFuture[S]]
            // If the resulting Future is completed, there's no reason
            // to chain cancelable tokens
            if (!cf.isCompleted)
              cf.cancelable match {
                case cRef2: ChainedCancelable =>
                  // Chaining ensures we don't leak
                  cRef2.forwardTo(cRef)
                case cRef2 =>
                  if (!cRef2.isInstanceOf[IsDummy]) cRef := cRef2
              }

            // Returning underlying b/c otherwise we leak memory in
            // infinite loops
            cf.underlying

          case _ =>
            nextRef
        }
      }
    )

    CancelableFuture(f2, cRef)
  }
}

object CancelableFuture extends internal.CancelableFutureForPlatform {
  /** Builder for a [[CancelableFuture]].
    *
    * @param underlying is an underlying `Future` reference that will respond to `onComplete` calls
    * @param cancelable is a [[monix.execution.Cancelable Cancelable]]
    *        that can be used to cancel the active computation
    */
  def apply[A](underlying: Future[A], cancelable: Cancelable): CancelableFuture[A] =
    new Async[A](underlying, cancelable)

  /** Promotes a strict `value` to a [[CancelableFuture]] that's
    * already complete.
    *
    * @param value is the value that's going to be signaled in the
    *        `onComplete` callback.
    */
  def successful[A](value: A): CancelableFuture[A] =
    new Pure[A](Success(value))

  /** Promotes a strict `Throwable` to a [[CancelableFuture]] that's
    * already complete with a failure.
    *
    * @param e is the error that's going to be signaled in the
    *        `onComplete` callback.
    */
  def failed[A](e: Throwable): CancelableFuture[A] =
    new Pure[A](Failure(e))

  /** Promotes a strict `value` to a [[CancelableFuture]] that's
    * already complete.
    *
    * Alias for [[successful]].
    *
    * @param value is the value that's going to be signaled in the
    *        `onComplete` callback.
    */
  def pure[A](value: A): CancelableFuture[A] =
    successful(value)

  /** Promotes a strict `Throwable` to a [[CancelableFuture]] that's
    * already complete with a failure.
    *
    * Alias for [[failed]].
    *
    * @param e is the error that's going to be signaled in the
    *        `onComplete` callback.
    */
  def raiseError[A](e: Throwable): CancelableFuture[A] =
    failed(e)

  /** An already completed [[CancelableFuture]]. */
  val unit: CancelableFuture[Unit] =
    successful(())

  /** Returns a [[CancelableFuture]] instance that will never complete. */
  final def never[A]: CancelableFuture[A] =
    Never

  /** Promotes a strict `Try[A]` to a [[CancelableFuture]] that's
    * already complete.
    *
    * @param value is the `Try[A]` value that's going to be signaled
    *        in the `onComplete` callback.
    */
  def fromTry[A](value: Try[A]): CancelableFuture[A] =
    new Pure[A](value)

  /** Given a registration function that can execute an asynchronous
    * process, executes it and builds a [[CancelableFuture]] value
    * out of it.
    *
    * The given `registration` function can return a [[Cancelable]]
    * reference that can be used to cancel the executed async process.
    * This reference can be [[Cancelable.empty empty]].
    *
    * {{{
    *   def delayedResult[A](f: => A)(implicit s: Scheduler): CancelableFuture[A] =
    *     CancelableFuture.async { complete =>
    *       val task = s.scheduleOnce(10.seconds) { complete(Try(f)) }
    *
    *       Cancelable { () =>
    *         println("Cancelling!")
    *         task.cancel()
    *       }
    *     }
    * }}}
    *
    * This is much like working with Scala's
    * [[scala.concurrent.Promise Promise]], only safer.
    */
  def async[A](register: (Try[A] => Unit) => Cancelable)(implicit ec: ExecutionContext): CancelableFuture[A] = {

    val p = Promise[A]()
    val cRef = SingleAssignCancelable()

    // Light async boundary to guard against stack overflows
    ec.execute(new TrampolinedRunnable {
      def run(): Unit = {
        try {
          cRef := register(p.complete)
        } catch {
          case e if NonFatal(e) =>
            if (!p.tryComplete(Failure(e)))
              ec.reportFailure(e)
        }
      }
    })

    CancelableFuture(p.future, cRef)
  }

  /** A [[CancelableFuture]] instance that will never complete. */
  private[execution] object Never extends CancelableFuture[Nothing] {
    def onComplete[U](f: (Try[Nothing]) => U)(implicit executor: ExecutionContext): Unit = ()

    val isCompleted = false
    val value = None

    def cancelable = Cancelable.empty
    def underlying = this

    @scala.throws[Exception](classOf[Exception])
    def result(atMost: Duration)(implicit permit: CanAwait): Nothing =
      throw new TimeoutException("This CancelableFuture will never finish!")

    @scala.throws[InterruptedException](classOf[InterruptedException])
    @scala.throws[TimeoutException](classOf[TimeoutException])
    def ready(atMost: Duration)(implicit permit: CanAwait): this.type =
      throw new TimeoutException("This CancelableFuture will never finish!")

    def cancel(): Unit = ()

    override def transform[S](f: (Try[Nothing]) => Try[S])(implicit executor: ExecutionContext): CancelableFuture[S] =
      this
    override def transformWith[S](f: (Try[Nothing]) => Future[S])(
      implicit executor: ExecutionContext): CancelableFuture[S] =
      this
  }

  /** An internal [[CancelableFuture]] implementation. */
  private[execution] final class Pure[+A](immediate: Try[A]) extends CancelableFuture[A] {
    def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this
    def result(atMost: Duration)(implicit permit: CanAwait): A = immediate.get

    def cancelable = Cancelable.empty
    val underlying = Future.fromTry(immediate)

    def cancel(): Unit = ()
    def isCompleted: Boolean = true
    def value: Option[Try[A]] = underlying.value

    def onComplete[U](f: (Try[A]) => U)(implicit executor: ExecutionContext): Unit =
      executor.execute(new Runnable { def run(): Unit = f(immediate) })
  }

  /** An actual [[CancelableFuture]] implementation; internal. */
  private[execution] final case class Async[+A](underlying: Future[A], cancelable: Cancelable)
    extends CancelableFuture[A] {

    override def onComplete[U](f: (Try[A]) => U)(implicit executor: ExecutionContext): Unit =
      underlying.onComplete(f)(executor)
    override def isCompleted: Boolean =
      underlying.isCompleted
    override def value: Option[Try[A]] =
      underlying.value

    @throws[Exception](classOf[Exception])
    def result(atMost: Duration)(implicit permit: CanAwait): A =
      underlying.result(atMost)(permit)

    @throws[InterruptedException](classOf[InterruptedException])
    @throws[TimeoutException](classOf[TimeoutException])
    def ready(atMost: Duration)(implicit permit: CanAwait): this.type = {
      underlying.ready(atMost)(permit)
      this
    }

    override def cancel(): Unit =
      cancelable.cancel()
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy