diff --git a/build.sbt b/build.sbt index ded58b20..4b3bd10b 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,5 @@ val catsVersion = "2.6.0" -val catsEffectVersion = "2.5.0" +val catsEffectVersion = "3.1.0" val utilVersion = "21.2.0" val finagleVersion = "21.2.0" diff --git a/effect/src/main/scala/io/catbird/util/effect/FutureInstances.scala b/effect/src/main/scala/io/catbird/util/effect/FutureInstances.scala index 89e4eb58..47be1be3 100644 --- a/effect/src/main/scala/io/catbird/util/effect/FutureInstances.scala +++ b/effect/src/main/scala/io/catbird/util/effect/FutureInstances.scala @@ -1,14 +1,15 @@ package io.catbird.util.effect -import cats.effect.{ Bracket, ExitCase } +import cats.effect.ExitCase import com.twitter.util.{ Future, Monitor } import io.catbird.util.FutureMonadError import java.lang.Throwable import scala.Unit +import cats.effect.MonadCancel trait FutureInstances { - implicit final val futureBracketInstance: Bracket[Future, Throwable] = - new FutureMonadError with Bracket[Future, Throwable] { + implicit final val futureBracketInstance: MonadCancel[Future, Throwable] = + new FutureMonadError with MonadCancel[Future, Throwable] { final def bracketCase[A, B](acquire: Future[A])(use: A => Future[B])( release: (A, ExitCase[Throwable]) => Future[Unit] ): Future[B] = diff --git a/effect/src/main/scala/io/catbird/util/effect/RerunnableContextShift.scala b/effect/src/main/scala/io/catbird/util/effect/RerunnableContextShift.scala index 761d2b98..876a7543 100644 --- a/effect/src/main/scala/io/catbird/util/effect/RerunnableContextShift.scala +++ b/effect/src/main/scala/io/catbird/util/effect/RerunnableContextShift.scala @@ -1,6 +1,5 @@ package io.catbird.util.effect -import cats.effect.ContextShift import com.twitter.util.{ Future, FuturePool, Promise } import io.catbird.util.Rerunnable diff --git a/effect/src/main/scala/io/catbird/util/effect/RerunnableTimer.scala b/effect/src/main/scala/io/catbird/util/effect/RerunnableTimer.scala index 67a510f5..c27fc151 100644 --- a/effect/src/main/scala/io/catbird/util/effect/RerunnableTimer.scala +++ b/effect/src/main/scala/io/catbird/util/effect/RerunnableTimer.scala @@ -1,12 +1,13 @@ package io.catbird.util.effect -import cats.effect.{ Clock, Timer } +import cats.effect.Clock import io.catbird.util.Rerunnable import com.twitter.util.Future import com.twitter.util import scala.Unit import scala.concurrent.duration.FiniteDuration +import cats.effect.Temporal /** * Can be used to construct a `cats.effect.Timer` instance for `Rerunnable` which let's you delay execution or @@ -35,7 +36,7 @@ object RerunnableTimer { } } -final private[effect] class RerunnableTimer private (implicit underlyingTimer: util.Timer) extends Timer[Rerunnable] { +final private[effect] class RerunnableTimer private (implicit underlyingTimer: util.Timer) extends Temporal[Rerunnable] { override val clock: Clock[Rerunnable] = RerunnableClock() diff --git a/effect/src/main/scala/io/catbird/util/effect/package.scala b/effect/src/main/scala/io/catbird/util/effect/package.scala index 539005e7..b325064f 100644 --- a/effect/src/main/scala/io/catbird/util/effect/package.scala +++ b/effect/src/main/scala/io/catbird/util/effect/package.scala @@ -1,17 +1,18 @@ package io.catbird.util -import cats.effect.{ Async, ContextShift, ExitCase, IO } +import cats.effect.{ Async, ExitCase, IO } import com.twitter.util.{ Future, Return, Throw, Try } import java.lang.Throwable import scala.util.{ Left, Right } +import cats.effect.Spawn package object effect extends FutureInstances with RerunnableInstances { /** * Converts the `Future` to `F` without changing the underlying execution (same thread pool!). */ - def futureToAsync[F[_], A](fa: => Future[A])(implicit F: Async[F]): F[A] = F.async { k => + def futureToAsync[F[_], A](fa: => Future[A])(implicit F: Async[F]): F[A] = F.async_ { k => fa.respond { case Return(a) => k(Right[Throwable, A](a)) case Throw(err) => k(Left[Throwable, A](err)) @@ -26,8 +27,8 @@ package object effect extends FutureInstances with RerunnableInstances { * the `Future` is running on a thread pool controlled by the library (e.g. the underlying Netty pool). * It also is closer to the behavior of `IO.fromFuture` for Scala futures which also shifts back. */ - def futureToAsyncAndShift[F[_], A](fa: => Future[A])(implicit F: Async[F], CS: ContextShift[F]): F[A] = - F.guarantee(futureToAsync[F, A](fa))(CS.shift) + def futureToAsyncAndShift[F[_], A](fa: => Future[A])(implicit F: Async[F]): F[A] = + F.guarantee(futureToAsync[F, A](fa), Spawn[F].cede) /** * Converts the `Rerunnable` to `F` without changing the underlying execution (same thread pool!). @@ -39,7 +40,7 @@ package object effect extends FutureInstances with RerunnableInstances { * The same as `rerunnableToIO` but doesn't stay on the thread pool of the `Rerunnable` and instead shifts execution * back to the one provided by `ContextShift[F]` (which is usually the default one). */ - final def rerunnableToIOAndShift[A](fa: Rerunnable[A])(implicit CS: ContextShift[IO]): IO[A] = + final def rerunnableToIOAndShift[A](fa: Rerunnable[A]): IO[A] = futureToAsyncAndShift[IO, A](fa.run) /** diff --git a/effect/src/test/scala/io/catbird/util/effect/ContextShiftingSuite.scala b/effect/src/test/scala/io/catbird/util/effect/ContextShiftingSuite.scala index f96b013a..19ae3f1f 100644 --- a/effect/src/test/scala/io/catbird/util/effect/ContextShiftingSuite.scala +++ b/effect/src/test/scala/io/catbird/util/effect/ContextShiftingSuite.scala @@ -1,6 +1,6 @@ package io.catbird.util.effect -import cats.effect.{ ContextShift, IO } +import cats.effect.IO import com.twitter.util.{ ExecutorServiceFuturePool, Future, FuturePool } import org.scalatest.Outcome import org.scalatest.funsuite.FixtureAnyFunSuite diff --git a/effect/src/test/scala/io/catbird/util/effect/RerunnableContextShiftSuite.scala b/effect/src/test/scala/io/catbird/util/effect/RerunnableContextShiftSuite.scala index b58bba20..30638863 100644 --- a/effect/src/test/scala/io/catbird/util/effect/RerunnableContextShiftSuite.scala +++ b/effect/src/test/scala/io/catbird/util/effect/RerunnableContextShiftSuite.scala @@ -1,6 +1,6 @@ package io.catbird.util.effect -import cats.effect.{ ContextShift, IO, Sync } +import cats.effect.{ IO, Sync } import com.twitter.util.{ Await, Future, FuturePool } import io.catbird.util.Rerunnable import org.scalatest.Outcome diff --git a/effect/src/test/scala/io/catbird/util/effect/RerunnableSuite.scala b/effect/src/test/scala/io/catbird/util/effect/RerunnableSuite.scala index ccc2d765..7d27a020 100644 --- a/effect/src/test/scala/io/catbird/util/effect/RerunnableSuite.scala +++ b/effect/src/test/scala/io/catbird/util/effect/RerunnableSuite.scala @@ -3,7 +3,7 @@ package io.catbird.util.effect import cats.effect.laws.discipline.EffectTests import cats.effect.laws.discipline.arbitrary.catsEffectLawsArbitraryForIO import cats.effect.laws.util.{ TestContext, TestInstances } -import cats.effect.{ Bracket, IO } +import cats.effect.IO import cats.instances.either._ import cats.instances.int._ import cats.instances.tuple._ @@ -15,6 +15,7 @@ import io.catbird.util.{ ArbitraryInstances, Rerunnable } import org.scalatest.funsuite.AnyFunSuite import org.scalatest.prop.Configuration import org.typelevel.discipline.scalatest.FunSuiteDiscipline +import cats.effect.MonadCancel class RerunnableSuite extends AnyFunSuite @@ -35,7 +36,7 @@ class RerunnableSuite var monitoredException: Throwable = null val monitor = Monitor.mk { case e => monitoredException = e; true; } - val rerunnable = Bracket[Rerunnable, Throwable] + val rerunnable = MonadCancel[Rerunnable, Throwable] .bracket(Rerunnable.Unit)(_ => Rerunnable.raiseError(useException))(_ => Rerunnable.raiseError(releaseException)) .liftToTry diff --git a/effect/src/test/scala/io/catbird/util/effect/RerunnableTimerSuite.scala b/effect/src/test/scala/io/catbird/util/effect/RerunnableTimerSuite.scala index 24bd2a64..eec80f14 100644 --- a/effect/src/test/scala/io/catbird/util/effect/RerunnableTimerSuite.scala +++ b/effect/src/test/scala/io/catbird/util/effect/RerunnableTimerSuite.scala @@ -1,6 +1,5 @@ package io.catbird.util.effect -import cats.effect.Timer import org.scalatest.Outcome import org.scalatest.funsuite.FixtureAnyFunSuite import com.twitter.util @@ -8,6 +7,7 @@ import com.twitter.util.{ Await, Future } import io.catbird.util.Rerunnable import scala.concurrent.duration._ +import cats.effect.Temporal class RerunnableTimerSuite extends FixtureAnyFunSuite { @@ -16,13 +16,13 @@ class RerunnableTimerSuite extends FixtureAnyFunSuite { } test("A timer can be used to delay execution") { f => - implicit val timer: Timer[Rerunnable] = RerunnableTimer(f.twitterTimer) + implicit val timer: Temporal[Rerunnable] = RerunnableTimer(f.twitterTimer) val result = Await.result( Future.selectIndex( Vector( for { - _ <- Timer[Rerunnable].sleep(100.milliseconds).run + _ <- Temporal[Rerunnable].sleep(100.milliseconds).run r <- Future.value("slow") } yield r, Future.value("fast").delayed(util.Duration.fromMilliseconds(50))(f.twitterTimer)