From ace83fc9111e11964ea83b49fb615a1f16cf1504 Mon Sep 17 00:00:00 2001 From: Tyler Chan Date: Tue, 10 Jan 2023 00:39:52 +0800 Subject: [PATCH 1/6] Add two new combinators: `cedeMap` and `intercede` --- core/shared/src/main/scala/cats/effect/IO.scala | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/shared/src/main/scala/cats/effect/IO.scala b/core/shared/src/main/scala/cats/effect/IO.scala index af63a7452a..1745047899 100644 --- a/core/shared/src/main/scala/cats/effect/IO.scala +++ b/core/shared/src/main/scala/cats/effect/IO.scala @@ -1316,6 +1316,18 @@ object IO extends IOCompanionPlatform with IOLowPriorityImplicits { */ def cede: IO[Unit] = Cede + /** + * Functor map, but causes a reschedule before and after `f` + */ + def cedeMap[A, B](fa: IO[A])(f: A => B): IO[B] = + (fa <* cede).map(a => f(a)).guarantee(cede) + + /** + * causes a reschedule before and after `fa` + */ + def intercede[A](fa: IO[A]): IO[A] = + cede *> fa.guarantee(cede) + /** * This is a low-level API which is meant for implementors, please use `background`, `start`, * `async`, or `Deferred` instead, depending on the use case From afe219ada9c2e6a3fa4c2379113668375c9db11f Mon Sep 17 00:00:00 2001 From: Tyler Chan Date: Tue, 10 Jan 2023 21:03:08 +0800 Subject: [PATCH 2/6] Add two new combinators: `cedeMap` and `intercede` --- .../src/main/scala/cats/effect/IO.scala | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/core/shared/src/main/scala/cats/effect/IO.scala b/core/shared/src/main/scala/cats/effect/IO.scala index 1745047899..68b26b1ddb 100644 --- a/core/shared/src/main/scala/cats/effect/IO.scala +++ b/core/shared/src/main/scala/cats/effect/IO.scala @@ -497,6 +497,20 @@ sealed abstract class IO[+A] private () extends IOPlatform[A] { */ def map[B](f: A => B): IO[B] = IO.Map(this, f, Tracing.calculateTracingEvent(f)) + /** + * Functor map, but causes a reschedule before and after `f`. For more information, checkout + * `cede` in the companion object. + */ + def cedeMap[B](f: A => B): IO[B] = + (this <* IO.cede).map(a => f(a)).guarantee(IO.cede) + + /** + * Causes a reschedule before and after `fa`. For more information, checkout `cede` in the + * companion object. + */ + def intercede: IO[A] = + IO.cede *> this.guarantee(IO.cede) + /** * Applies rate limiting to this `IO` based on provided backpressure semantics. * @@ -1316,18 +1330,6 @@ object IO extends IOCompanionPlatform with IOLowPriorityImplicits { */ def cede: IO[Unit] = Cede - /** - * Functor map, but causes a reschedule before and after `f` - */ - def cedeMap[A, B](fa: IO[A])(f: A => B): IO[B] = - (fa <* cede).map(a => f(a)).guarantee(cede) - - /** - * causes a reschedule before and after `fa` - */ - def intercede[A](fa: IO[A]): IO[A] = - cede *> fa.guarantee(cede) - /** * This is a low-level API which is meant for implementors, please use `background`, `start`, * `async`, or `Deferred` instead, depending on the use case From d6f9f685bc4c63ce452857c5c466410c15c40092 Mon Sep 17 00:00:00 2001 From: Tyler Chan Date: Wed, 11 Jan 2023 22:02:42 +0800 Subject: [PATCH 3/6] Add two new combinators: `cedeMap` and `intercede` --- .../scala/cats/effect/kernel/GenSpawn.scala | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/GenSpawn.scala b/kernel/shared/src/main/scala/cats/effect/kernel/GenSpawn.scala index 69516761a1..24cd88679a 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/GenSpawn.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/GenSpawn.scala @@ -282,6 +282,27 @@ trait GenSpawn[F[_], E] extends MonadCancel[F, E] with Unique[F] { */ def cede: F[Unit] + /** + * Functor map, but causes a reschedule before and after `f` + */ + def cedeMap[A, B](fa: F[A])(f: A => B): F[B] = + for { + a <- fa + _ <- cede + b = f(a) + _ <- cede + } yield b + + /** + * Causes a reschedule before and after `fa` + */ + def intercede[A](fa: F[A]): F[A] = + for { + _ <- cede + a <- fa + _ <- cede + } yield a + /** * A low-level primitive for racing the evaluation of two fibers that returns the [[Outcome]] * of the winner and the [[Fiber]] of the loser. The winner of the race is considered to be From 9b2ba64b3acba2ad356d2d2fe43c8641e2caf42c Mon Sep 17 00:00:00 2001 From: Tyler Chan Date: Wed, 11 Jan 2023 23:22:02 +0800 Subject: [PATCH 4/6] Add two new combinators: `cedeMap` and `intercede` --- .../main/scala/cats/effect/kernel/GenSpawn.scala | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/GenSpawn.scala b/kernel/shared/src/main/scala/cats/effect/kernel/GenSpawn.scala index 24cd88679a..7918784827 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/GenSpawn.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/GenSpawn.scala @@ -286,22 +286,13 @@ trait GenSpawn[F[_], E] extends MonadCancel[F, E] with Unique[F] { * Functor map, but causes a reschedule before and after `f` */ def cedeMap[A, B](fa: F[A])(f: A => B): F[B] = - for { - a <- fa - _ <- cede - b = f(a) - _ <- cede - } yield b + (fa <* cede).map(a => f(a)).guarantee(cede) /** * Causes a reschedule before and after `fa` */ def intercede[A](fa: F[A]): F[A] = - for { - _ <- cede - a <- fa - _ <- cede - } yield a + cede *> fa.guarantee(cede) /** * A low-level primitive for racing the evaluation of two fibers that returns the [[Outcome]] From ed15013511e27c5879c65ca8c0267b2f96e18924 Mon Sep 17 00:00:00 2001 From: Tyler Chan Date: Thu, 12 Jan 2023 01:20:32 +0800 Subject: [PATCH 5/6] Add two new combinators: `cedeMap` and `intercede` --- .../scala/cats/effect/kernel/syntax/GenSpawnSyntax.scala | 6 ++++++ .../src/test/scala/cats/effect/kernel/SyntaxSpec.scala | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenSpawnSyntax.scala b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenSpawnSyntax.scala index f2820b5d84..cbb3320785 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenSpawnSyntax.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenSpawnSyntax.scala @@ -59,4 +59,10 @@ final class GenSpawnOps[F[_], A, E] private[syntax] (private val wrapped: F[A]) implicit F: GenSpawn[F, E] ): F[(Outcome[F, E, A], Outcome[F, E, B])] = F.bothOutcome(wrapped, another) + + def cedeMap[B](f: A => B)(implicit F: GenSpawn[F, E]): F[B] = + F.cedeMap(wrapped)(f) + + def intercede(implicit F: GenSpawn[F, E]): F[A] = + F.intercede(wrapped) } diff --git a/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala b/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala index 5046313cc4..f42b4e9945 100644 --- a/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala +++ b/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala @@ -139,6 +139,11 @@ class SyntaxSpec extends Specification { val result = target.bothOutcome(another) result: F[(Outcome[F, E, A], Outcome[F, E, B])] } + + { + val result = target.intercede + result: F[A] + } } def spawnForwarder[F[_]: Spawn] = From a5b867001efdc2d46c2e75a3c55cf799980b297a Mon Sep 17 00:00:00 2001 From: Tyler Chan Date: Sat, 14 Jan 2023 12:24:05 +0800 Subject: [PATCH 6/6] Add two new combinators: `cedeMap` and `intercede` --- .../src/test/scala/cats/effect/kernel/SyntaxSpec.scala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala b/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala index f42b4e9945..2a837e0e4d 100644 --- a/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala +++ b/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala @@ -104,7 +104,8 @@ class SyntaxSpec extends Specification { } } - def genSpawnSyntax[F[_], A, B, E](target: F[A], another: F[B])(implicit F: GenSpawn[F, E]) = { + def genSpawnSyntax[F[_], A, B, E](target: F[A], another: F[B], f: A => B)( + implicit F: GenSpawn[F, E]) = { import syntax.spawn._ GenSpawn[F]: F.type @@ -140,6 +141,11 @@ class SyntaxSpec extends Specification { result: F[(Outcome[F, E, A], Outcome[F, E, B])] } + { + val result = target.cedeMap(f) + result: F[B] + } + { val result = target.intercede result: F[A]