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

kyo.core.scala Maven / Gradle / Ivy

There is a newer version: 0.8.5
Show newest version
package kyo

import kyo.locals.Locals.State

import scala.runtime.AbstractFunction0
import scala.runtime.AbstractFunction1
import scala.util.control.NonFatal
import scala.language.higherKinds

import locals._

object core {

  import internal._

  abstract class Handler[M[_], E <: Effect[M, E], S] {
    def pure[T](v: T): M[T]
    def handle[T](ex: Throwable): T > E = throw ex
    def apply[T, U, S2](m: M[T], f: T => U > (E with S2)): U > (E with S with S2)
  }

  abstract class Effect[M[_], E <: Effect[M, E]] {
    self: E =>

    def accepts[M2[_], E2 <: Effect[M2, E2]](other: Effect[M2, E2]): Boolean = this eq other

    inline
    protected final def suspend[T, S](v: M[T] > S): T > (S with E) = {
      def suspendLoop(v: M[T] > S): T > (S with E) = {
        v match {
          case kyo: Kyo[MX, EX, Any, M[T], S] @unchecked =>
            new KyoCont[MX, EX, Any, T, S with E](kyo) {
              def apply(v: Any > (S with E), s: Safepoint[MX, EX], l: Locals.State) =
                suspendLoop(kyo(v, s, l))
            }
          case _ =>
            new KyoRoot[M, E, T, S with E](v.asInstanceOf[M[T]], this) {}
        }
      }
      if (v == null) {
        throw new NullPointerException
      }
      suspendLoop(v)
    }

    inline
    protected final def handle[T, S, S2](v: T > (E with S))(implicit
        h: Handler[M, E, S2],
        s: Safepoint[M, E],
        f: Flat[T > (E with S)]
    ): M[T] > (S with S2) = {
      def handleLoop(
          v: T > (S with S2 with E)
      ): M[T] > (S with S2) =
        v match {
          case kyo: Kyo[M, E, Any, T, S with E] @unchecked if (accepts(kyo.effect)) =>
            if (kyo.isRoot) {
              kyo.value.asInstanceOf[M[T] > S]
            } else {
              handleLoop(h[Any, T, S with E](
                  kyo.value,
                  kyo(_, s, Locals.State.empty)
              ))
            }
          case kyo: Kyo[MX, EX, Any, T, S with E] @unchecked =>
            new KyoCont[MX, EX, Any, M[T], S with S2](kyo) {
              def apply(v: Any > (S with S2), s2: Safepoint[MX, EX], l: Locals.State) =
                handleLoop {
                  try kyo(v, s2, l)
                  catch {
                    case ex if (NonFatal(ex)) =>
                      h.handle(ex)
                  }
                }
            }
          case _ =>
            h.pure(v.asInstanceOf[T])
        }
      if (v == null) {
        throw new NullPointerException
      }
      handleLoop(v)
    }

    override def toString = getClass.getSimpleName()
  }

  inline
  def transform[T, S, U, S2](v: T > S)( inline f: T => (U > S2)): U > (S with S2) = {
    def transformLoop(v: T > S): U > (S with S2) =
      v match {
        case kyo: Kyo[MX, EX, Any, T, S] @unchecked =>
          new KyoCont[MX, EX, Any, U, S with S2](kyo) {
            def apply(v: Any > (S with S2), s: Safepoint[MX, EX], l: Locals.State) = {
              val n = kyo(v, s, l)
              if (s.check()) {
                s.suspend[U, S with S2](transformLoop(n))
                  .asInstanceOf[U > (S with S2)]
              } else {
                transformLoop(n)
              }
            }
          }
        case _ =>
          f(v.asInstanceOf[T])
      }
    if (v == null) {
      throw new NullPointerException
    }
    transformLoop(v)
  }

  trait Safepoint[M[_], E <: Effect[M, _]] {
    def check(): Boolean
    def suspend[T, S](v: => T > S): T > (S with E)
  }

  object Safepoint {
    private val _noop = new Safepoint[MX, EX] {
      def check()                    = false
      def suspend[T, S](v: => T > S) = v
    }
    implicit def noop[M[_], E <: Effect[M, E]]: Safepoint[M, E] =
      _noop.asInstanceOf[Safepoint[M, E]]
  }

  private[kyo] object internal {

    def deepHandle[M[_], E <: Effect[M, E], T](e: E)(v: T > E)(implicit
        h: DeepHandler[M, E],
        s: Safepoint[M, E]
    ): M[T] = {
      def deepHandleLoop(v: T > E): M[T] =
        v match {
          case kyo: Kyo[M, E, Any, T, E] @unchecked =>
            require(kyo.effect == e, "Unhandled effect: " + kyo.effect)
            h.apply(kyo.value, (v: Any) => deepHandleLoop(kyo(v, s, Locals.State.empty)))
          case _ =>
            h.pure(v.asInstanceOf[T])
        }
      if (v == null) {
        throw new NullPointerException
      }
      deepHandleLoop(v)
    }

    type MX[_] = Any
    type EX    = Effect[MX, _]

    abstract class DeepHandler[M[_], E <: Effect[M, E]] {
      def pure[T](v: T): M[T]
      def apply[T, U](m: M[T], f: T => M[U]): M[U]
    }

    abstract class Kyo[M[_], E <: Effect[M, _], T, U, S] {
      def value: M[T]
      def effect: E
      def apply(v: T > S, s: Safepoint[M, E], l: Locals.State): U > S
      def isRoot: Boolean = false
    }

    abstract class KyoRoot[M[_], E <: Effect[M, _], T, S](v: M[T], e: E)
        extends Kyo[M, E, T, T, S] {
      final def value  = v
      final def effect = e
      final def apply(v: T > S, s: Safepoint[M, E], l: Locals.State) =
        v
      override final def isRoot = true
    }

    abstract class KyoCont[M[_], E <: Effect[M, _], T, U, S](prev: Kyo[M, E, T, _, _])
        extends Kyo[M, E, T, U, S] {
      final val value: M[T] = prev.value
      final val effect: E   = prev.effect
    }

    inline
    implicit def fromKyo[M[_], E <: Effect[M, _], T, U, S](v: Kyo[M, E, T, U, S]): U > S =
      v.asInstanceOf[U > S]
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy