Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #497 provide Runtime-based Async & Temporal instances for any R type #502

Merged
merged 1 commit into from
Feb 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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