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

izumi.functional.bio.impl.AsyncZio.scala Maven / Gradle / Ivy

The newest version!
package izumi.functional.bio.impl

import izumi.functional.bio.Exit.ZIOExit
import izumi.functional.bio.data.{Morphism3, RestoreInterruption2}
import izumi.functional.bio.{Async2, Exit, Fiber2, __PlatformSpecific}
import izumi.fundamentals.platform.language.Quirks.Discarder
import zio._izumicompat_.{__ZIORaceCompat, __ZIOWithFiberRuntime}
import zio.internal.stacktracer.{InteropTracer, Tracer}
import zio.stacktracer.TracingImplicits.disableAutoTrace
import zio.ZIO

import java.util.concurrent.CompletionStage
import java.util.concurrent.atomic.AtomicBoolean
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Try

object AsyncZio extends AsyncZio[Any]

open class AsyncZio[R] extends Async2[ZIO[R, +_, +_]] {
  @inline override final def InnerF: this.type = this

  @inline override final def unit: ZIO[Any, Nothing, Unit] = ZIO.unit
  @inline override final def pure[A](a: A): ZIO[Any, Nothing, A] = ZIO.succeed(a)(Tracer.instance.empty)
  @inline override final def sync[A](effect: => A): ZIO[Any, Nothing, A] = {
    val byName: () => A = () => effect
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    ZIO.succeed(effect)
  }
  @inline override final def syncThrowable[A](effect: => A): ZIO[Any, Throwable, A] = {
    val byName: () => A = () => effect
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    ZIO.attempt(effect)
  }
  @inline override final def suspend[A](effect: => ZIO[R, Throwable, A]): ZIO[R, Throwable, A] = {
    val byName: () => ZIO[R, Throwable, A] = () => effect
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    ZIO.suspend(effect)
  }
  @inline override final def suspendSafe[E, A](effect: => ZIO[R, E, A]): ZIO[R, E, A] = {
    val byName: () => ZIO[R, E, A] = () => effect
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    ZIO.suspendSucceed(effect)
  }

  @inline override final def fail[E](v: => E): ZIO[Any, E, Nothing] = {
    val byName: () => E = () => v
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    ZIO.fail(v)
  }
  @inline override final def terminate(v: => Throwable): ZIO[Any, Nothing, Nothing] = {
    val byName: () => Throwable = () => v
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    ZIO.die(v)
  }

  @inline override final def fromEither[E, A](effect: => Either[E, A]): ZIO[Any, E, A] = {
    val byName: () => Either[E, A] = () => effect
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    ZIO.fromEither(effect)
  }
  @inline override final def fromOption[E, A](errorOnNone: => E)(effect: => Option[A]): ZIO[Any, E, A] = {
    val byName: () => Option[A] = () => effect
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    ZIO.fromEither(effect.toRight(errorOnNone))
  }
  @inline override final def fromTry[A](effect: => Try[A]): ZIO[Any, Throwable, A] = {
    val byName: () => Try[A] = () => effect
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    ZIO.fromTry(effect)
  }

  @inline override final def void[E, A](r: ZIO[R, E, A]): ZIO[R, E, Unit] = r.unit(Tracer.instance.empty)
  @inline override final def map[E, A, B](r: ZIO[R, E, A])(f: A => B): ZIO[R, E, B] = r.map(f)(InteropTracer.newTrace(f))
  @inline override final def as[E, A, B](r: ZIO[R, E, A])(v: => B): ZIO[R, E, B] = {
    val byName: () => B = () => v
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    r.as(v)
  }

  @inline override final def tapError[E, A, E1 >: E](r: ZIO[R, E, A])(f: E => ZIO[R, E1, Unit]): ZIO[R, E1, A] = r.tapError(f)(implicitly, InteropTracer.newTrace(f))
  @inline override final def leftMap[E, A, E2](r: ZIO[R, E, A])(f: E => E2): ZIO[R, E2, A] = r.mapError(f)(implicitly, InteropTracer.newTrace(f))
  @inline override final def leftFlatMap[E, A, E2](r: ZIO[R, E, A])(f: E => ZIO[R, Nothing, E2]): ZIO[R, E2, A] =
    r.flatMapError(f)(implicitly, InteropTracer.newTrace(f))
  @inline override final def flip[E, A](r: ZIO[R, E, A]): ZIO[R, A, E] = r.flip(Tracer.instance.empty)
  @inline override final def bimap[E, A, E2, B](r: ZIO[R, E, A])(f: E => E2, g: A => B): ZIO[R, E2, B] = r.mapBoth(f, g)(implicitly, InteropTracer.newTrace(f))

  @inline override final def flatMap[E, A, B](r: ZIO[R, E, A])(f0: A => ZIO[R, E, B]): ZIO[R, E, B] = r.flatMap(f0)(InteropTracer.newTrace(f0))
  @inline override final def tap[E, A](r: ZIO[R, E, A], f: A => ZIO[R, E, Unit]): ZIO[R, E, A] = r.tap(f)(InteropTracer.newTrace(f))
  @inline override final def tapBoth[E, A, E1 >: E](r: ZIO[R, E, A])(err: E => ZIO[R, E1, Unit], succ: A => ZIO[R, E1, Unit]): ZIO[R, E1, A] =
    r.tapBoth(err, succ)(implicitly, InteropTracer.newTrace(err))
  @inline override final def flatten[E, A](r: ZIO[R, E, ZIO[R, E, A]]): ZIO[R, E, A] = ZIO.flatten(r)(Tracer.instance.empty)
  @inline override final def *>[E, A, B](f: ZIO[R, E, A], next: => ZIO[R, E, B]): ZIO[R, E, B] = {
    val byName: () => ZIO[R, E, B] = () => next
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    f *> next
  }
  @inline override final def <*[E, A, B](f: ZIO[R, E, A], next: => ZIO[R, E, B]): ZIO[R, E, A] = {
    val byName: () => ZIO[R, E, B] = () => next
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    f <* next
  }
  @inline override final def map2[E, A, B, C](r1: ZIO[R, E, A], r2: => ZIO[R, E, B])(f: (A, B) => C): ZIO[R, E, C] = {
    val byName: () => ZIO[R, E, B] = () => r2
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    r1.zipWith(r2)(f)
  }

  @inline override final def iterateWhile[E, A](r: ZIO[R, E, A])(p: A => Boolean): ZIO[R, E, A] = r.repeatWhile(p)(InteropTracer.newTrace(p))
  @inline override final def iterateUntil[E, A](r: ZIO[R, E, A])(p: A => Boolean): ZIO[R, E, A] = r.repeatUntil(p)(InteropTracer.newTrace(p))

  @inline override final def leftMap2[E, A, E2, E3](firstOp: ZIO[R, E, A], secondOp: => ZIO[R, E2, A])(f: (E, E2) => E3): ZIO[R, E3, A] = {
    val byName: () => ZIO[R, E2, A] = () => secondOp
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    firstOp.catchAll(e => secondOp.mapError(f(e, _)))
  }
  @inline override final def orElse[E, A, E2](r: ZIO[R, E, A], f: => ZIO[R, E2, A]): ZIO[R, E2, A] = {
    val byName: () => ZIO[R, E2, A] = () => f
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    r.orElse(f)
  }

  @inline override final def redeem[E, A, E2, B](r: ZIO[R, E, A])(err: E => ZIO[R, E2, B], succ: A => ZIO[R, E2, B]): ZIO[R, E2, B] =
    r.foldZIO(err, succ)(implicitly, InteropTracer.newTrace(err))
  @inline override final def catchAll[E, A, E2](r: ZIO[R, E, A])(f: E => ZIO[R, E2, A]): ZIO[R, E2, A] = r.catchAll(f)(implicitly, InteropTracer.newTrace(f))
  @inline override final def catchSome[E, A, E1 >: E](r: ZIO[R, E, A])(f: PartialFunction[E, ZIO[R, E1, A]]): ZIO[R, E1, A] =
    r.catchSome(f)(implicitly, InteropTracer.newTrace(f))

  @inline override final def guarantee[E, A](f: ZIO[R, E, A], cleanup: ZIO[R, Nothing, Unit]): ZIO[R, E, A] = f.ensuring(cleanup)(Tracer.instance.empty)
  @inline override final def attempt[E, A](r: ZIO[R, E, A]): ZIO[R, Nothing, Either[E, A]] = r.either(implicitly, Tracer.instance.empty)
  @inline override final def redeemPure[E, A, B](r: ZIO[R, E, A])(err: E => B, succ: A => B): ZIO[R, Nothing, B] =
    r.fold(err, succ)(implicitly, InteropTracer.newTrace(err))

  @inline override final def retryWhile[E, A](r: ZIO[R, E, A])(f: E => Boolean): ZIO[R, E, A] = r.retryWhile(f)(implicitly, InteropTracer.newTrace(f))
  @inline override final def retryWhileF[E, A](r: ZIO[R, E, A])(f: E => ZIO[R, Nothing, Boolean]): ZIO[R, E, A] =
    r.retryWhileZIO(f)(implicitly, InteropTracer.newTrace(f))

  @inline override final def retryUntil[E, A](r: ZIO[R, E, A])(f: E => Boolean): ZIO[R, E, A] = r.retryUntil(f)(implicitly, InteropTracer.newTrace(f))
  @inline override final def retryUntilF[E, A](r: ZIO[R, E, A])(f: E => ZIO[R, Nothing, Boolean]): ZIO[R, E, A] =
    r.retryUntilZIO(f)(implicitly, InteropTracer.newTrace(f))

  @inline override final def fromOptionOr[E, A](valueOnNone: => A, r: ZIO[R, E, Option[A]]): ZIO[R, E, A] = {
    val byName: () => A = () => valueOnNone
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    r.someOrElse(valueOnNone)
  }

  @inline override final def fromOptionF[E, A](fallbackOnNone: => ZIO[R, E, A], r: ZIO[R, E, Option[A]]): ZIO[R, E, A] = {
    val byName: () => ZIO[R, E, A] = () => fallbackOnNone
    implicit val trace: zio.Trace = InteropTracer.newTrace(byName)

    r.someOrElseZIO(fallbackOnNone)
  }

  @inline override final def bracket[E, A, B](acquire: ZIO[R, E, A])(release: A => ZIO[R, Nothing, Unit])(use: A => ZIO[R, E, B]): ZIO[R, E, B] = {
    ZIO.acquireReleaseWith(acquire)(release)(use)(InteropTracer.newTrace(release))
  }
  @inline override final def bracketCase[E, A, B](
    acquire: ZIO[R, E, A]
  )(release: (A, Exit[E, B]) => ZIO[R, Nothing, Unit]
  )(use: A => ZIO[R, E, B]
  ): ZIO[R, E, B] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(release)

    ZIO.acquireReleaseExitWith[R, E, A](acquire)((a, exit: zio.Exit[E, B]) => ZIOExit.withIsInterruptedF(i => release(a, ZIOExit.toExit(exit)(i))))(use)
  }
  @inline override final def guaranteeCase[E, A](f: ZIO[R, E, A], cleanup: Exit[E, A] => ZIO[R, Nothing, Unit]): ZIO[R, E, A] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(cleanup)

    f.onExit(exit => ZIOExit.withIsInterruptedF(cleanup apply ZIOExit.toExit(exit)(_)))
  }

  @inline override final def traverse[E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]] =
    ZIO.foreach(l.toList)(f)(implicitly, InteropTracer.newTrace(f))
  @inline override final def sequence[E, A](l: Iterable[ZIO[R, E, A]]): ZIO[R, E, List[A]] = ZIO.collectAll(l.toList)(implicitly, Tracer.instance.empty)
  @inline override final def traverse_[E, A](l: Iterable[A])(f: A => ZIO[R, E, Unit]): ZIO[R, E, Unit] = ZIO.foreachDiscard(l)(f)(InteropTracer.newTrace(f))
  @inline override final def sequence_[E](l: Iterable[ZIO[R, E, Unit]]): ZIO[R, E, Unit] = ZIO.foreachDiscard(l)(identity)(Tracer.instance.empty)
  @inline override final def filter[E, A](l: Iterable[A])(f: A => ZIO[R, E, Boolean]): ZIO[R, E, List[A]] = ZIO.filter(l.toList)(f)(implicitly, InteropTracer.newTrace(f))

  @inline override final def foldLeft[E, A, AC](l: Iterable[A])(z: AC)(f: (AC, A) => ZIO[R, E, AC]): ZIO[R, E, AC] = {
    ZIO.foldLeft(l)(z)(f)(InteropTracer.newTrace(f))
  }

  @inline override final def find[E, A](l: Iterable[A])(f: A => ZIO[R, E, Boolean]): ZIO[R, E, Option[A]] = {
    val trace = InteropTracer.newTrace(f)

    ZIO.collectFirst(l)(a => f(a).map(if (_) Some(a) else None)(trace))(trace)
  }

  @inline override final def collectFirst[E, A, B](l: Iterable[A])(f: A => ZIO[R, E, Option[B]]): ZIO[R, E, Option[B]] = {
    ZIO.collectFirst(l)(f)(InteropTracer.newTrace(f))
  }

  @inline override final def sandbox[E, A](r: ZIO[R, E, A]): ZIO[R, Exit.FailureUninterrupted[E], A] = {
    implicit val trace: zio.Trace = Tracer.instance.empty

    // Assume no *external* interruption:
    // either we're interrupted here - ergo we don't return from here anyway,
    // or we're in an uninterruptible region - ergo we're not interrupted.
    // In BIO (and cats-effect), only external interruption counts as 'interruption'
    // Internal interruption is not a valid state (and is treated as a defect - Exit.Termination)
    r.sandbox.mapError(ZIOExit.toExitUninterrupted)
  }

  @inline override final def yieldNow: ZIO[Any, Nothing, Unit] = ZIO.yieldNow(Tracer.instance.empty)
  @inline override final def never: ZIO[Any, Nothing, Nothing] = ZIO.never(Tracer.instance.empty)

  @inline override final def async[E, A](register: (Either[E, A] => Unit) => Unit): ZIO[Any, E, A] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(register)

    ZIO.async(cb => register(cb apply _.fold(ZIO.fail(_), ZIO.succeed(_))))
  }
  @inline override final def asyncF[E, A](register: (Either[E, A] => Unit) => ZIO[R, E, Unit]): ZIO[R, E, A] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(register)

    ZIO.asyncZIO(cb => register(cb apply _.fold(ZIO.fail(_), ZIO.succeed(_))))
  }
  @inline override final def asyncCancelable[E, A](register: (Either[E, A] => Unit) => Canceler): ZIO[R, E, A] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(register)

    ZIO.asyncInterrupt[R, E, A] {
      cb =>
        val canceler = register(cb apply _.fold(ZIO.fail(_), ZIO.succeed(_)))
        Left(canceler)
    }
  }

  @inline override final def fromFuture[A](mkFuture: ExecutionContext => Future[A]): ZIO[Any, Throwable, A] = {
    ZIO.fromFuture(mkFuture)(InteropTracer.newTrace(mkFuture))
  }
  @inline override final def fromFutureJava[A](javaFuture: => CompletionStage[A]): ZIO[Any, Throwable, A] = {
    __PlatformSpecific.fromFutureJava(javaFuture)
  }

  @inline override final def uninterruptible[E, A](r: ZIO[R, E, A]): ZIO[R, E, A] = r.uninterruptible(Tracer.instance.empty)

  @inline override final def race[E, A](r1: ZIO[R, E, A], r2: ZIO[R, E, A]): ZIO[R, E, A] = {
    implicit val trace: zio.Trace = Tracer.instance.empty

    __ZIORaceCompat.raceFirst(r1.interruptible, r2.interruptible)
  }

  @inline override final def racePairUnsafe[E, A, B](
    r1: ZIO[R, E, A],
    r2: ZIO[R, E, B],
  ): ZIO[R, E, Either[(Exit[E, A], Fiber2[ZIO[R, +_, +_], E, B]), (Fiber2[ZIO[R, +_, +_], E, A], Exit[E, B])]] = {
    implicit val trace: zio.Trace = Tracer.instance.empty

    val interrupted1 = new AtomicBoolean(true)
    val interrupted2 = new AtomicBoolean(true)
    __ZIORaceCompat.raceWith(
      ZIOExit.ZIOSignalOnNoExternalInterruptFailure(r1.interruptible)(sync(interrupted1.set(false))),
      ZIOExit.ZIOSignalOnNoExternalInterruptFailure(r2.interruptible)(sync(interrupted2.set(false))),
    )(
      { case (l, f) => ZIO.succeed(Left((ZIOExit.toExit(l)(interrupted1.get()), Fiber2.fromZIO(sync(interrupted2.get()))(f)))) },
      { case (r, f) => ZIO.succeed(Right((Fiber2.fromZIO(sync(interrupted1.get()))(f), ZIOExit.toExit(r)(interrupted2.get())))) },
    )
  }

  @inline override final def parTraverseN[E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(f)

    ZIO
      .foreachPar(l.toList)(f(_).interruptible)
      .withParallelism(maxConcurrent)
  }
  @inline override final def parTraverseN_[E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, Unit] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(f)

    ZIO
      .foreachParDiscard(l)(f(_).interruptible)
      .withParallelism(maxConcurrent)
  }
  @inline override final def parTraverseNCore[E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]] = {
    ZIO.suspendSucceed(parTraverseN(java.lang.Runtime.getRuntime.availableProcessors() max 2)(l)(f))(InteropTracer.newTrace(f))
  }
  @inline override final def parTraverseNCore_[E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, Unit] = {
    ZIO.suspendSucceed(parTraverseN_(java.lang.Runtime.getRuntime.availableProcessors() max 2)(l)(f))(InteropTracer.newTrace(f))
  }
  @inline override final def parTraverse[E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(f)

    // do not force unlimited parallelism here, obey 'regional parallelism' (unlimited by default)
    ZIO.foreachPar(l.toList)(f(_).interruptible)
  }
  @inline override final def parTraverse_[E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, Unit] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(f)

    // do not force unlimited parallelism here, obey 'regional parallelism' (unlimited by default)
    ZIO.foreachParDiscard(l)(f(_).interruptible)
  }

  @inline override final def zipWithPar[E, A, B, C](fa: ZIO[R, E, A], fb: ZIO[R, E, B])(f: (A, B) => C): ZIO[R, E, C] = {
    fa.zipWithPar(fb)(f)(InteropTracer.newTrace(f))
  }
  @inline override final def zipPar[E, A, B](fa: ZIO[R, E, A], fb: ZIO[R, E, B]): ZIO[R, E, (A, B)] = {
    fa.<&>(fb)(zio.Zippable.Zippable2[A, B], Tracer.instance.empty)
  }
  @inline override final def zipParLeft[E, A, B](fa: ZIO[R, E, A], fb: ZIO[R, E, B]): ZIO[R, E, A] = {
    fa.<&(fb)(Tracer.instance.empty)
  }
  @inline override final def zipParRight[E, A, B](fa: ZIO[R, E, A], fb: ZIO[R, E, B]): ZIO[R, E, B] = {
    fa.&>(fb)(Tracer.instance.empty)
  }

  @inline override final def sendInterruptToSelf: ZIO[Any, Nothing, Unit] = {
    implicit val trace: zio.Trace = Tracer.instance.empty

    def loopUntilInterrupted: ZIO[Any, Nothing, Unit] =
      ZIO.descriptorWith(d => if (d.interrupters.isEmpty) ZIO.yieldNow *> loopUntilInterrupted else ZIO.unit)

    for {
      _ <- __ZIOWithFiberRuntime.ZIOWithFiberRuntime[Any, Nothing, Unit]((thisFiber, _) => thisFiber.interruptAsFork(thisFiber.id))
      _ <- loopUntilInterrupted
    } yield ()
  }

  @inline override final def currentEC: ZIO[Any, Nothing, ExecutionContext] = ZIO.executor(Tracer.instance.empty).map(_.asExecutionContext)(Tracer.instance.empty)
  @inline override final def onEC[E, A](ec: ExecutionContext)(f: ZIO[R, E, A]): ZIO[R, E, A] = f.onExecutionContext(ec)(Tracer.instance.empty)

  @inline override final def uninterruptibleExcept[E, A](r: RestoreInterruption2[ZIO[R, +_, +_]] => ZIO[R, E, A]): ZIO[R, E, A] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(r)

    ZIO.uninterruptibleMask {
      restore =>
        val restoreMorphism: Morphism3[ZIO, ZIO] = Morphism3(restore(_))
        r(restoreMorphism)
    }
  }

  @inline override final def bracketExcept[E, A, B](
    acquire: RestoreInterruption2[ZIO[R, +_, +_]] => ZIO[R, E, A]
  )(release: (A, Exit[E, B]) => ZIO[R, Nothing, Unit]
  )(use: A => ZIO[R, E, B]
  ): ZIO[R, E, B] = {
    implicit val trace: zio.Trace = InteropTracer.newTrace(acquire)

    ZIO.uninterruptibleMask[R, E, B] {
      restore =>
        val restoreMorphism: Morphism3[ZIO, ZIO] = Morphism3(restore(_))
        acquire(restoreMorphism).flatMap {
          a =>
            ZIO
              .suspendSucceed(restore(use(a)))
              .exit
              .flatMap {
                e =>
                  ZIOExit
                    .withIsInterruptedF(i => release(a, Exit.ZIOExit.toExit(e)(i)))
                    .foldCauseZIO(
                      cause2 => ZIO.refailCause(e.foldExit(_ ++ cause2, _ => cause2)),
                      _ => ZIO.done(e),
                    )
              }
        }
    }
  }

  disableAutoTrace.discard()
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy