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

com.thoughtworks.continuation.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 ThoughtWorks, 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 com.thoughtworks

import java.util.concurrent.atomic.AtomicReference

import com.thoughtworks.continuation._

import scala.annotation.tailrec
import scala.collection.immutable.Queue
import scala.concurrent.{ExecutionContext, Future, Promise}
import scalaz.{-\/, @@, Applicative, BindRec, ContT, Monad, Tags, Trampoline, Zip, \/, \/-}
import scalaz.Free.Trampoline
import scalaz.Tags.Parallel
import scala.language.higherKinds
import scala.language.existentials
import scala.util.Try

/** The name space that contains [[Continuation]] and utilities for `Continuation`.
  * @author 杨博 (Yang Bo)
  */
object continuation {

  @inline
  private def suspendTrampoline[R](a: => Trampoline[R]) = Trampoline.suspend(a)

  private[continuation] trait OpaqueTypes {
    type Continuation[R, +A]
    type ParallelContinuation[R, A] = Continuation[R, A] @@ Parallel

    def toFunction[R, A](continuation: Continuation[R, A]): (A => Trampoline[R]) => Trampoline[R]
    def fromFunction[R, A](continuation: (A => Trampoline[R]) => Trampoline[R]): Continuation[R, A]
  }

  private[continuation] sealed trait ParallelZipState[A, B]

  private[continuation] object ParallelZipState {

    private[continuation] final case class GotNeither[A, B]() extends ParallelZipState[A, B]

    private[continuation] final case class GotA[A, B](a: A) extends ParallelZipState[A, B]

    private[continuation] final case class GotB[A, B](b: B) extends ParallelZipState[A, B]

  }

  @inline
  private[continuation] val opaqueTypes: OpaqueTypes = new OpaqueTypes {
    type Continuation[R, +A] = (A => Trampoline[R]) => Trampoline[R]

    def toFunction[R, A](continuation: Continuation[R, A]): (A => Trampoline[R]) => Trampoline[R] = continuation
    def fromFunction[R, A](continuation: (A => Trampoline[R]) => Trampoline[R]): Continuation[R, A] = continuation
  }

  /** The stack-safe and covariant version of [[scalaz.Cont]].
    * @note The underlying type of this `Continuation` is `(A => Trampoline[R]) => Trampoline[R]`.
    * @see [[ContinuationOps]] for extension methods for this `Continuation`.
    * @see [[UnitContinuation]] if you want to use this `Continuation` as an asynchronous task.
    * @template
    */
  type Continuation[R, +A] = opaqueTypes.Continuation[R, A]

  /** A [[Continuation]] whose response type is [[scala.Unit]].
    *
    * This `UnitContinuation` type can be used as an asynchronous task.
    *
    * @see [[UnitContinuationOps]] for extension methods for this `UnitContinuationOps`.
    * @see [[ParallelContinuation]] for parallel version of this `UnitContinuation`.
    * @note This `UnitContinuation` type does not support exception handling.
    * @see [[com.thoughtworks.future.Future Future]] for asynchronous task that supports exception handling.
    * @template
    */
  type UnitContinuation[+A] = Continuation[Unit, A]

  /** Extension methods for [[Continuation]]
    * @group Implicit Views
    */
  implicit final class ContinuationOps[R, A](val underlying: Continuation[R, A]) extends AnyVal {

    @inline
    def toContT: ContT[Trampoline, R, A] = {
      ContT[Trampoline, R, A](opaqueTypes.toFunction[R, A](underlying))
    }

    /** Runs the [[underlying]] continuation.
      *
      * @param continue the callback function that will be called once the [[underlying]] continuation complete.
      * @note The JVM call stack will grow if there are recursive calls to [[onComplete]] in `continue`.
      *       A `StackOverflowError` may occurs if the recursive calls are very deep.
      * @see [[safeOnComplete]] in case of `StackOverflowError`.
      *
      */
    @inline
    def onComplete(continue: A => R): R = {
      opaqueTypes
        .toFunction(underlying) { a =>
          Trampoline.delay(continue(a))
        }
        .run
    }

    /** Runs the [[underlying]] continuation like [[onComplete]], except this `safeOnComplete` is stack-safe. */
    @inline
    def safeOnComplete(continue: A => Trampoline[R]): Trampoline[R] = {
      Continuation.safeOnComplete(underlying)(continue)
    }

  }
  @inline
  def reset[A](continuation: Continuation[A, A]): A = {
    continuation.onComplete(identity)
  }

  private final class BlockingState[A] {
    @volatile var result: Option[A] = None
  }

  /** Extension methods for [[UnitContinuation]]
    * @group Implicit Views
    */
  implicit final class UnitContinuationOps[A](val underlying: UnitContinuation[A]) extends AnyVal {

    /** Returns a memorized [[scala.concurrent.Future]] for the [[underlying]] [[UnitContinuation]].*/
    def toScalaFuture: Future[A] = {
      val promise = Promise[A]
      ContinuationOps[Unit, A](underlying).onComplete { a =>
        val _ = promise.success(a)
      }
      promise.future
    }

    /** Blocking waits and returns the result value of the [[underlying]] [[UnitContinuation]].*/
    def blockingAwait(): A = {
      val state = new BlockingState[A]
      state.synchronized {
        underlying.onComplete { a =>
          state.synchronized {
            state.result = Some(a)
            state.notify()
          }
        }
        while (state.result.isEmpty) {
          state.wait()
        }
      }
      val Some(a) = state.result
      a
    }
  }

  /** [[scalaz.Tags.Parallel Parallel]]-tagged type of [[UnitContinuation]] that needs to be executed in parallel when using an [[scalaz.Applicative]] instance
    *
    * @example Given two [[ParallelContinuation]]s that contain immediate values,
    *
    *          {{{
    *          import com.thoughtworks.continuation._
    *          import scalaz.Tags.Parallel
    *          import scalaz.syntax.all._
    *
    *          val pc0: ParallelContinuation[Int] = Parallel(Continuation.now[Unit, Int](40))
    *          val pc1: ParallelContinuation[Int] = Parallel(Continuation.now[Unit, Int](2))
    *          }}}
    *
    *          when map them together,
    *
    *          {{{
    *          val result: ParallelContinuation[Int] = (pc0 |@| pc1)(_ + _)
    *          }}}
    *
    *          then the result should be a `ParallelContinuation` as well,
    *          and it is able to convert to a normal [[Continuation]]
    *
    *          {{{
    *          Parallel.unwrap(result).map {
    *            _ should be(42)
    *          }
    *          }}}
    *
    * @example Given two [[ParallelContinuation]]s,
    *          each of them modifies a `var`,
    *
    *          {{{
    *          import com.thoughtworks.continuation._
    *          import scalaz.Tags.Parallel
    *          import scalaz.syntax.all._
    *
    *          var count0 = 0
    *          var count1 = 0
    *
    *          val pc0: ParallelContinuation[Unit] = Parallel(Continuation.delay {
    *            count0 += 1
    *          })
    *          val pc1: ParallelContinuation[Unit] = Parallel(Continuation.delay {
    *            count1 += 1
    *          })
    *          }}}
    *
    *          when map them together,
    *
    *          {{{
    *          val result: ParallelContinuation[Unit] = (pc0 |@| pc1) { (u0: Unit, u1: Unit) => }
    *          }}}
    *
    *          then the two vars have not been modified right now,
    *
    *          {{{
    *          count0 should be(0)
    *          count1 should be(0)
    *          }}}
    *
    *          when the result `ParallelContinuation` get done,
    *          then two vars should be modified only once for each.
    *
    *          {{{
    *          Parallel.unwrap(result).map { _: Unit =>
    *            count0 should be(1)
    *            count1 should be(1)
    *          }
    *          }}}
    *
    * @template
    */
  type ParallelContinuation[A] = UnitContinuation[A] @@ Parallel

  /**
    * @group Type class instances
    */
  implicit object continuationParallelApplicative
      extends Applicative[ParallelContinuation]
      with Zip[ParallelContinuation] {

    override def apply2[A, B, C](fa: => ParallelContinuation[A], fb: => ParallelContinuation[B])(
        f: (A, B) => C): ParallelContinuation[C] = {
      val Parallel(continuation) = tuple2(fa, fb)
      Parallel(continuationMonad.map(continuation) { case (a, b) => f(a, b) })
    }

    override def map[A, B](fa: ParallelContinuation[A])(f: (A) => B): ParallelContinuation[B] = {
      val Parallel(continuation) = fa
      Parallel(continuationMonad.map(continuation)(f))
    }

    override def point[A](a: => A): ParallelContinuation[A] = Parallel(continuationMonad[Unit].point[A](a))

    override def tuple2[A, B](fa: => ParallelContinuation[A],
                              fb: => ParallelContinuation[B]): ParallelContinuation[(A, B)] = {
      import ParallelZipState._

      val continuation
        : Continuation[Unit, (A, B)] = Continuation.safeAsync { (continue: ((A, B)) => Trampoline[Unit]) =>
        def listenA(state: AtomicReference[ParallelZipState[A, B]]): Trampoline[Unit] = {
          @tailrec
          def continueA(state: AtomicReference[ParallelZipState[A, B]], a: A): Trampoline[Unit] = {
            state.get() match {
              case oldState @ GotNeither() =>
                if (state.compareAndSet(oldState, GotA(a))) {
                  Trampoline.done(())
                } else {
                  continueA(state, a)
                }
              case GotA(_) =>
                val forkState = new AtomicReference[ParallelZipState[A, B]](GotA(a))
                listenB(forkState)
              case GotB(b) =>
                suspendTrampoline {
                  continue((a, b))
                }
            }
          }
          Continuation.safeOnComplete(Parallel.unwrap(fa))(continueA(state, _))
        }
        def listenB(state: AtomicReference[ParallelZipState[A, B]]): Trampoline[Unit] = {
          @tailrec
          def continueB(state: AtomicReference[ParallelZipState[A, B]], b: B): Trampoline[Unit] = {
            state.get() match {
              case oldState @ GotNeither() =>
                if (state.compareAndSet(oldState, GotB(b))) {
                  Trampoline.done(())
                } else {
                  continueB(state, b)
                }
              case GotB(_) =>
                val forkState = new AtomicReference[ParallelZipState[A, B]](GotB(b))
                listenA(forkState)
              case GotA(a) =>
                suspendTrampoline {
                  continue((a, b))
                }
            }
          }
          Continuation.safeOnComplete(Parallel.unwrap(fb))(continueB(state, _))
        }
        val state = new AtomicReference[ParallelZipState[A, B]](GotNeither())
        import scalaz.syntax.bind._
        listenA(state) >> listenB(state)
      }
      Parallel(continuation)
    }

    override def zip[A, B](fa: => ParallelContinuation[A],
                           fb: => ParallelContinuation[B]): ParallelContinuation[(A, B)] = {
      tuple2(fa, fb)
    }

    override def ap[A, B](fa: => ParallelContinuation[A])(
        f: => ParallelContinuation[(A) => B]): ParallelContinuation[B] = {
      import scalaz.syntax.tag._
      Parallel(continuationMonad[Unit].map[(A, A => B), B](tuple2(fa, f).unwrap) {
        pair: (A, A => B) =>
          pair._2(pair._1)
      })
    }

  }

  object UnitContinuation {

    /** Returns a [[UnitContinuation]] of a blocking operation that will run on `executionContext`. */
    def execute[A](a: => A)(implicit executionContext: ExecutionContext): UnitContinuation[A] = {
      Continuation.async { continue: (A => Unit) =>
        executionContext.execute(new Runnable {
          override def run(): Unit = continue(a)
        })
      }
    }

    /** A synonym of [[Continuation.async]] */
    def async[A](start: (A => Unit) => Unit): UnitContinuation[A] = {
      Continuation.async(start)
    }

    /** A synonym of [[Continuation.now]] */
    @inline
    def now[A](a: A): UnitContinuation[A] = {
      Continuation.now(a)
    }

    /** A synonym of [[Continuation.delay]] */
    def delay[A](a: => A): UnitContinuation[A] = {
      Continuation.delay(a)
    }

    /** A synonym of [[Continuation.safeAsync]] */
    def safeAsync[A](start: (A => Trampoline[Unit]) => Trampoline[Unit]): UnitContinuation[A] = {
      Continuation.safeAsync(start)
    }

    def suspend[A](continuation: => UnitContinuation[A]): UnitContinuation[A] = {
      Continuation.suspend(continuation)
    }

    /** A synonym of [[Continuation.fromContT]] */
    @inline
    def fromContT[A](contT: ContT[Trampoline, Unit, _ <: A]): UnitContinuation[A] = {
      Continuation.fromContT(contT)
    }

    @inline
    def apply[A](start: (A => Trampoline[Unit]) => Trampoline[Unit]): UnitContinuation[A] = {
      safeAsync(start)
    }

    /** A synonym of [[Continuation.unapply]] */
    @inline
    def unapply[A](continuation: UnitContinuation[A]): Some[(A => Trampoline[Unit]) => Trampoline[Unit]] = {
      Continuation.unapply[Unit, A](continuation)
    }
  }

  /** The companion object for [[Continuation]].
    *
    */
  object Continuation {

    private final case class Async[R, A](start: (A => R) => R) extends ((A => Trampoline[R]) => Trampoline[R]) {
      override def apply(continue: (A) => Trampoline[R]): Trampoline[R] = {
        Trampoline.delay {
          start { a =>
            continue(a).run
          }
        }
      }
    }

    /** Returns a [[Continuation]] of an asynchronous operation.
      *
      * @see [[safeAsync]] in case of `StackOverflowError`.
      */
    def async[R, A](start: (A => R) => R): Continuation[R, A] = {
      safeAsync(Async(start))
    }

    private final case class Now[R, A](a: A) extends ((A => Trampoline[R]) => Trampoline[R]) {
      override def apply(continue: (A) => Trampoline[R]): Trampoline[R] = continue(a)
    }

    /** Returns a [[Continuation]] whose value is always `a`. */
    @inline
    def now[R, A](a: A): Continuation[R, A] = safeAsync(Now(a))

    private final case class Delay[R, A](block: () => A) extends ((A => Trampoline[R]) => Trampoline[R]) {
      override def apply(continue: (A) => Trampoline[R]): Trampoline[R] = suspendTrampoline(continue(block()))
    }

    /** Returns a [[Continuation]] of a blocking operation */
    @inline
    def delay[R, A](block: => A): Continuation[R, A] = safeAsync(Delay(block _))

    @inline
    private[thoughtworks] def safeOnComplete[R, A](continuation: Continuation[R, A])(
        continue: A => Trampoline[R]): Trampoline[R] = {
      suspendTrampoline {
        opaqueTypes.toFunction(continuation)(continue)
      }
    }

    /** Returns a [[Continuation]] of an asynchronous operation like [[async]] except this method is stack-safe. */
    def safeAsync[R, A](start: (A => Trampoline[R]) => Trampoline[R]): Continuation[R, A] = {
      opaqueTypes.fromFunction[R, A](start)
    }

    final case class Suspend[R, A](continuation: () => Continuation[R, A])
        extends ((A => Trampoline[R]) => Trampoline[R]) {
      def apply(continue: (A) => Trampoline[R]): Trampoline[R] = {
        continuation().safeOnComplete(continue)
      }
    }

    def suspend[R, A](continuation: => Continuation[R, A]): Continuation[R, A] = {
      safeAsync(Suspend(continuation _))
    }

    @inline
    def apply[R, A](start: (A => Trampoline[R]) => Trampoline[R]): Continuation[R, A] = {
      safeAsync(start)
    }

    /** Creates a [[Continuation]] from the raw [[scalaz.ContT]] */
    @inline
    def fromContT[R, A](contT: ContT[Trampoline, R, _ <: A]): Continuation[R, A] = {
      opaqueTypes.fromFunction[R, A] { continue =>
        contT.run(continue)
      }
    }

    /** Extracts the underlying [[scalaz.ContT]] of `continuation`
      *
      * @example This `unapply` can be used in pattern matching expression.
      *          {{{
      *          import com.thoughtworks.continuation.Continuation
      *          val Continuation(f) = Continuation.now[Unit, Int](42)
      *          f should be(a[Function1[_, _]])
      *          }}}
      *
      */
    @inline
    def unapply[R, A](continuation: Continuation[R, A]): Some[(A => Trampoline[R]) => Trampoline[R]] = {
      Some(opaqueTypes.toFunction[R, A](continuation))
    }
  }

  private final case class Bind[R, A, B](fa: Continuation[R, A], f: (A) => Continuation[R, B])
      extends ((B => Trampoline[R]) => Trampoline[R]) {
    def apply(continue: (B) => Trampoline[R]): Trampoline[R] = {
      Continuation.safeOnComplete[R, A](fa) { a =>
        Continuation.safeOnComplete[R, B](f(a))(continue)
      }
    }
  }
  private final case class Map[R, A, B](fa: Continuation[R, A], f: (A) => B)
      extends ((B => Trampoline[R]) => Trampoline[R]) {
    def apply(continue: (B) => Trampoline[R]): Trampoline[R] = {
      Continuation.safeOnComplete(fa) { a: A =>
        suspendTrampoline(continue(f(a)))
      }
    }
  }

  private final case class Join[R, A](ffa: Continuation[R, Continuation[R, A]])
      extends ((A => Trampoline[R]) => Trampoline[R]) {
    def apply(continue: A => Trampoline[R]): Trampoline[R] = {
      Continuation.safeOnComplete[R, Continuation[R, A]](ffa) { fa =>
        Continuation.safeOnComplete[R, A](fa)(continue)
      }
    }
  }

  private final case class TailrecM[R, A, B](f: (A) => Continuation[R, A \/ B], a: A)
      extends ((B => Trampoline[R]) => Trampoline[R]) {
    def apply(continue: (B) => Trampoline[R]): Trampoline[R] = {
      def loop(a: A): Trampoline[R] = {
        Continuation.safeOnComplete(f(a)) {
          case -\/(a) =>
            loop(a)
          case \/-(b) =>
            suspendTrampoline(continue(b))
        }
      }
      loop(a)
    }

  }

  /**
    * @group Type class instances
    */
  @inline
  implicit def continuationMonad[R]
    : Monad[Continuation[R, `+?`]] with BindRec[Continuation[R, `+?`]] with Zip[Continuation[R, `+?`]] =
    new Monad[Continuation[R, `+?`]] with BindRec[Continuation[R, `+?`]] with Zip[Continuation[R, `+?`]] {

      @inline
      override def zip[A, B](a: => Continuation[R, A], b: => Continuation[R, B]): Continuation[R, (A, B)] = {
        tuple2(a, b)
      }

      override def bind[A, B](fa: Continuation[R, A])(f: (A) => Continuation[R, B]): Continuation[R, B] = {
        Continuation.safeAsync(Bind(fa, f))
      }

      @inline
      override def point[A](a: => A): Continuation[R, A] = {
        Continuation.delay(a)
      }

      override def tailrecM[A, B](f: (A) => Continuation[R, A \/ B])(a: A): Continuation[R, B] = {
        Continuation.safeAsync(TailrecM(f, a))
      }

      override def map[A, B](fa: Continuation[R, A])(f: (A) => B): Continuation[R, B] = {
        Continuation.safeAsync(Map(fa, f))
      }

      override def join[A](ffa: Continuation[R, Continuation[R, A]]): Continuation[R, A] = {
        Continuation.safeAsync(Join(ffa))
      }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy