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

tofu.Scoped.scala Maven / Gradle / Ivy

package tofu

import scala.concurrent.{ExecutionContext, Future}

import cats._
import tofu.higherKind.{Mid, Point, PureK}
import tofu.internal.EffectComp
import tofu.internal.instances.ScopedInstance
import tofu.kernel.types._
import tofu.syntax.funk._

/** can be used for scoped transformations
  * @tparam Tag
  *   arbitrary type tag f type Execute[F[_]] = ScopedExecute[Scoped.Main, F]
  *
  * type Blocks[F[_]] = Scoped[Scoped.Blocking, F] type BlockExec[F[_]] = ScopedExecute[Scoped.Blocking, F]
  *
  * type Calculates[F[_]] = Scoped[Scoped.Calculation, F] type CalcExec[F[_]] = ScopedExecute[Scoped.Calculation, F]or
  * discriminating scopes
  * @tparam F
  *   process type
  */
trait Scoped[Tag, F[_]] {
  def runScoped[A](fa: F[A]): F[A]

  final def asMid[A]: Mid[F, A] = fa => fa

  final def funK: F ~> F = funKFrom[F](fa => fa)

  final def tagged[NewTag]: Scoped[NewTag, F] = this.asInstanceOf[Scoped[NewTag, F]]

  final def midPoint: Point[Mid[F, _]] = new Point[Mid[F, _]] {
    def point[A]: Mid[F, A] = runScoped(_)
  }
}

object Scoped extends ScopedInstance with ScopedInstancesMacro {

  /** type tag for blocking scopes */
  type Blocking

  /** type tag for resource-consuming calculations */
  type Calculation

  /** type tag for the main scope */
  type Main

  def apply[Tag, F[_]](implicit sc: Scoped[Tag, F]): Scoped[Tag, F] = sc

  /** a helper for creating new instances of `Scoped`
    * {{{
    *   val instance: Scoped[Tag, F] = Scoped.make[Tag, F](fa => ...)
    * }}}
    */
  def make[Tag, F[_]] = new Make[Tag, F]

  class Make[Tag, F[_]](private val __ : Boolean = true) extends AnyVal         {
    type Arbitrary
    def apply(maker: Maker[Tag, F, Arbitrary]): Scoped[Tag, F] = maker
  }
  abstract class Maker[Tag, F[_], Arbitrary]             extends Scoped[Tag, F] {
    def arbApply(fa: F[Arbitrary]): F[Arbitrary]
    final def runScoped[A](fa: F[A]): F[A] = arbApply(fa.asInstanceOf[F[Arbitrary]]).asInstanceOf[F[A]]
  }

  /** could be used to define scopes with modified environment
    * {{{
    * case class MyContext(field: Field, ...) val newField:
    * Field = ??? type My[+A] = Env[MyContext, A] type Updated implicit val myScoped: Scoped[Updated, My] =
    * Scoped.local[MyContext](_.copy(field = newField))
    * }}}
    */
  def local[C]: Local[C] = new Local

  class Local[C](private val __ : Boolean = true) extends AnyVal {
    def apply[Tag, F[_]](transform: C => C)(implicit FL: F WithLocal C): Scoped[Tag, F] =
      make[Tag, F](FL.local(_)(transform))
  }

  /** helpful method to create middleware that executes all proceses in the given scope */
  def mid[Tag, U[_[_]], F[_]](implicit U: PureK[U], F: Scoped[Tag, F]): U[Mid[F, _]] = U.pureK(F.midPoint)
}

trait ScopedExecute[Tag, F[_]] extends Scoped[Tag, F] {
  def executionContext: F[ExecutionContext]

  def deferFutureAction[A](f: ExecutionContext => Future[A]): F[A]

  def deferFuture[A](f: => Future[A]): F[A] = deferFutureAction(_ => f)
}

object Execute extends EffectComp[Execute]

object Blocks extends EffectComp[Blocks]

object BlockExec extends EffectComp[BlockExec]

object Calculates extends EffectComp[Calculates]

object CalcExec extends EffectComp[CalcExec]




© 2015 - 2025 Weber Informatics LLC | Privacy Policy