Skip to content

Commit

Permalink
Fix #497 provide Runtime-based Async & Temporal instances for any R t…
Browse files Browse the repository at this point in the history
…ype (#502)
  • Loading branch information
neko-kai authored Feb 12, 2022
1 parent 1bafafc commit 4cd2db5
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 72 deletions.
6 changes: 4 additions & 2 deletions zio-interop-cats/js/src/main/scala/zio/interop/ZioAsync.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package zio.interop

import cats.effect.kernel.{ Async, Cont, Sync, Unique }
import zio.clock.Clock
import zio.{ Promise, RIO, ZIO }

import scala.concurrent.{ ExecutionContext, Future }

private class ZioAsync[R <: Clock] extends ZioTemporal[R, Throwable] with Async[RIO[R, _]] {
private abstract class ZioAsync[R]
extends ZioTemporal[R, Throwable]
with Async[RIO[R, _]]
with ZioBlockingEnv[R, Throwable] {

override final def evalOn[A](fa: F[A], ec: ExecutionContext): F[A] =
fa.on(ec)
Expand Down
19 changes: 11 additions & 8 deletions zio-interop-cats/jvm/src/main/scala/zio/interop/ZioAsync.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package zio.interop

import cats.effect.kernel.{ Async, Cont, Sync, Unique }
import zio.blocking.{ effectBlocking, effectBlockingInterrupt, Blocking }
import zio.clock.Clock
import zio.blocking.{ effectBlocking, effectBlockingInterrupt }
import zio.{ Promise, RIO, ZIO }

import scala.concurrent.{ ExecutionContext, Future }

private class ZioAsync[R <: Clock & Blocking] extends ZioTemporal[R, Throwable] with Async[RIO[R, _]] {
private abstract class ZioAsync[R]
extends ZioTemporal[R, Throwable]
with Async[RIO[R, _]]
with ZioBlockingEnv[R, Throwable] {

override final def evalOn[A](fa: F[A], ec: ExecutionContext): F[A] =
fa.on(ec)
Expand All @@ -22,9 +24,10 @@ private class ZioAsync[R <: Clock & Blocking] extends ZioTemporal[R, Throwable]
Async.defaultCont(body)(this)

override final def suspend[A](hint: Sync.Type)(thunk: => A): F[A] = hint match {
case Sync.Type.Delay => ZIO.effect(thunk)
case Sync.Type.Blocking => effectBlocking(thunk)
case Sync.Type.InterruptibleOnce | Sync.Type.InterruptibleMany => effectBlockingInterrupt(thunk)
case Sync.Type.Delay => ZIO.effect(thunk)
case Sync.Type.Blocking => blocking(thunk)
case Sync.Type.InterruptibleOnce => interruptible(many = false)(thunk)
case Sync.Type.InterruptibleMany => interruptible(many = true)(thunk)
}

override final def delay[A](thunk: => A): F[A] =
Expand All @@ -34,10 +37,10 @@ private class ZioAsync[R <: Clock & Blocking] extends ZioTemporal[R, Throwable]
ZIO.effectSuspend(thunk)

override final def blocking[A](thunk: => A): F[A] =
effectBlocking(thunk)
withBlocking(effectBlocking(thunk))

override final def interruptible[A](many: Boolean)(thunk: => A): F[A] =
effectBlockingInterrupt(thunk)
withBlocking(effectBlockingInterrupt(thunk))

override final def async[A](k: (Either[Throwable, A] => Unit) => F[Option[F[Unit]]]): F[A] =
Promise.make[Nothing, Unit].flatMap { promise =>
Expand Down
95 changes: 33 additions & 62 deletions zio-interop-cats/shared/src/main/scala/zio/interop/cats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import zio.clock.{ currentTime, nanoTime, Clock }
import zio.duration.Duration

import java.util.concurrent.atomic.AtomicBoolean
import scala.concurrent.{ ExecutionContext, Future }
import scala.concurrent.duration.*

object catz extends CatsEffectPlatform {
Expand Down Expand Up @@ -89,17 +88,17 @@ abstract class CatsEffectInstances extends CatsZioInstances {
implicit final def concurrentInstance[R, E]: GenConcurrent[ZIO[R, E, _], E] =
concurrentInstance0.asInstanceOf[GenConcurrent[ZIO[R, E, _], E]]

implicit final def asyncRuntimeInstance(implicit runtime: Runtime[Clock & CBlocking]): Async[Task] =
new ZioRuntimeAsync
implicit final def asyncRuntimeInstance[R](implicit runtime: Runtime[Clock & CBlocking]): Async[RIO[R, _]] =
new ZioRuntimeAsync(runtime.environment)

implicit final def temporalRuntimeInstance[E](implicit runtime: Runtime[Clock]): GenTemporal[IO[E, _], E] =
new ZioRuntimeTemporal[E]
implicit final def temporalRuntimeInstance[R, E](implicit runtime: Runtime[Clock]): GenTemporal[ZIO[R, E, _], E] =
new ZioRuntimeTemporal(runtime.environment)

private[this] val asyncInstance0: Async[RIO[Clock & CBlocking, _]] =
new ZioAsync
new ZioAsync[Clock & CBlocking] with ZioBlockingEnvIdentity[Clock & CBlocking, Throwable]

private[this] val temporalInstance0: Temporal[RIO[Clock, _]] =
new ZioTemporal
new ZioTemporal[Clock, Throwable] with ZioClockEnvIdentity[Clock, Throwable]

private[this] val concurrentInstance0: Concurrent[Task] =
new ZioConcurrent[Any, Throwable]
Expand Down Expand Up @@ -317,80 +316,52 @@ private final class ZioRef[R, E, A](ref: ERef[E, A]) extends effect.Ref[ZIO[R, E
ref.get
}

private class ZioTemporal[R <: Clock, E] extends ZioConcurrent[R, E] with GenTemporal[ZIO[R, E, _], E] {
private abstract class ZioTemporal[R, E]
extends ZioConcurrent[R, E]
with GenTemporal[ZIO[R, E, _], E]
with ZioClockEnv[R, E] {

override final def sleep(time: FiniteDuration): F[Unit] =
ZIO.sleep(Duration.fromScala(time))
withClock(ZIO.sleep(Duration.fromScala(time)))

override final val monotonic: F[FiniteDuration] =
nanoTime.map(FiniteDuration(_, NANOSECONDS))
withClock(nanoTime.map(FiniteDuration(_, NANOSECONDS)))

override final val realTime: F[FiniteDuration] =
currentTime(MILLISECONDS).map(FiniteDuration(_, MILLISECONDS))
withClock(currentTime(MILLISECONDS).map(FiniteDuration(_, MILLISECONDS)))
}

private class ZioRuntimeTemporal[E](implicit runtime: Runtime[Clock])
extends ZioConcurrent[Any, E]
with GenTemporal[IO[E, _], E] {
private class ZioRuntimeTemporal[R, E](environment: Clock) extends ZioTemporal[R, E] with ZioClockEnv[R, E] {

private[this] val underlying: GenTemporal[ZIO[Clock, E, _], E] = new ZioTemporal[Clock, E]
private[this] val clock: Clock = runtime.environment
override protected[this] def withClock[A](fa: ZIO[Clock, E, A]): ZIO[R, E, A] = fa.provide(environment)

override final def sleep(time: FiniteDuration): F[Unit] =
underlying.sleep(time).provide(clock)

override final val monotonic: F[FiniteDuration] =
underlying.monotonic.provide(clock)

override final val realTime: F[FiniteDuration] =
underlying.realTime.provide(clock)
}

private class ZioRuntimeAsync(implicit runtime: Runtime[Clock & CBlocking])
extends ZioRuntimeTemporal[Throwable]
with Async[Task] {

private[this] val underlying: Async[RIO[Clock & CBlocking, _]] = new ZioAsync[Clock & CBlocking]
private[this] val environment: Clock & CBlocking = runtime.environment

override final def evalOn[A](fa: F[A], ec: ExecutionContext): F[A] =
underlying.evalOn(fa, ec).provide(environment)

override final val executionContext: F[ExecutionContext] =
underlying.executionContext.provide(environment)

override final val unique: F[Unique.Token] =
underlying.unique.provide(environment)
private class ZioRuntimeAsync[R](environment: Clock & CBlocking) extends ZioAsync[R] with ZioBlockingEnv[R, Throwable] {

override final def cont[K, Q](body: Cont[F, K, Q]): F[Q] =
Async.defaultCont(body)(this)
override protected[this] def withClock[A](fa: RIO[Clock, A]): RIO[R, A] = fa.provide(environment)

override final def suspend[A](hint: Sync.Type)(thunk: => A): F[A] =
underlying.suspend(hint)(thunk).provide(environment)
override protected[this] def withBlocking[A](fa: RIO[CBlocking, A]): RIO[R, A] =
fa.provide(environment)(NeedsEnv.needsEnv)

override final def delay[A](thunk: => A): F[A] =
underlying.delay(thunk).provide(environment)

override final def defer[A](thunk: => F[A]): F[A] =
underlying.defer(thunk).provide(environment)

override final def blocking[A](thunk: => A): F[A] =
underlying.blocking(thunk).provide(environment)

override final def interruptible[A](many: Boolean)(thunk: => A): F[A] =
underlying.interruptible(many)(thunk).provide(environment)
}

override final def async[A](k: (Either[Throwable, A] => Unit) => F[Option[F[Unit]]]): F[A] =
underlying.async(k).provide(environment)
private trait ZioClockEnv[R, E] extends Any {
protected[this] def withClock[A](fa: ZIO[Clock, E, A]): ZIO[R, E, A]
}

override final def async_[A](k: (Either[Throwable, A] => Unit) => Unit): F[A] =
underlying.async_(k).provide(environment)
private trait ZioBlockingEnv[R, E] extends ZioClockEnv[R, E] {
protected[this] def withBlocking[A](fa: ZIO[CBlocking, E, A]): ZIO[R, E, A]
}

override final def fromFuture[A](fut: F[Future[A]]): F[A] =
underlying.fromFuture(fut).provide(environment)
private trait ZioClockEnvIdentity[R <: Clock, E] extends ZioClockEnv[R, E] {
override protected[this] def withClock[A](fa: ZIO[Clock, E, A]): ZIO[R, E, A] = fa
}

override final def never[A]: F[A] =
ZIO.never
private trait ZioBlockingEnvIdentity[R <: Clock & CBlocking, E]
extends ZioBlockingEnv[R, E]
with ZioClockEnvIdentity[R, E] {
override protected[this] def withBlocking[A](fa: ZIO[CBlocking, E, A]): ZIO[R, E, A] = fa
}

private class ZioMonadError[R, E] extends MonadError[ZIO[R, E, _], E] {
Expand Down

0 comments on commit 4cd2db5

Please sign in to comment.