From 993e6da86095d5c385b9ca58bf7d5ef8466aaad9 Mon Sep 17 00:00:00 2001 From: Ciprian Sofronia Date: Fri, 4 Mar 2022 18:32:52 +0200 Subject: [PATCH 1/4] Add receAllFirst --- .../shared/src/test/scala/zio/ZIOSpec.scala | 22 +++++++++++++++++++ core/shared/src/main/scala/zio/ZIO.scala | 15 +++++++++++++ 2 files changed, 37 insertions(+) diff --git a/core-tests/shared/src/test/scala/zio/ZIOSpec.scala b/core-tests/shared/src/test/scala/zio/ZIOSpec.scala index 229c95376021..06f82bf85d96 100644 --- a/core-tests/shared/src/test/scala/zio/ZIOSpec.scala +++ b/core-tests/shared/src/test/scala/zio/ZIOSpec.scala @@ -2671,6 +2671,28 @@ object ZIOSpec extends ZIOBaseSpec { b <- effect.await } yield assert(b)(equalTo(42)) } @@ zioTag(interruption), + testM("raceAllFirst interrupts losers on success") { + for { + s <- Promise.make[Nothing, Unit] + effect <- Promise.make[Nothing, Int] + winner = s.await *> IO.fromEither(Right(())) + losers = List(ZIO.bracket(s.succeed(()))(_ => effect.succeed(42))(_ => ZIO.infinity)) + race = winner raceAllFirst losers + _ <- race + b <- effect.await + } yield assert(b)(equalTo(42)) + } @@ zioTag(interruption), + testM("raceAllFirst interrupts losers on failure") { + for { + s <- Promise.make[Nothing, Unit] + effect <- Promise.make[Nothing, Int] + winner = s.await *> IO.fromEither(Left(new Exception)) + losers = List(ZIO.bracket(s.succeed(()))(_ => effect.succeed(42))(_ => ZIO.infinity)) + race = winner raceAllFirst losers + _ <- race.either + b <- effect.await + } yield assert(b)(equalTo(42)) + } @@ zioTag(interruption), testM("mergeAll") { val io = IO.mergeAll(List("a", "aa", "aaa", "aaaa").map(IO.succeed[String](_)))(0)((b, a) => b + a.length) diff --git a/core/shared/src/main/scala/zio/ZIO.scala b/core/shared/src/main/scala/zio/ZIO.scala index cd460ba4cad7..6748d0fbd370 100644 --- a/core/shared/src/main/scala/zio/ZIO.scala +++ b/core/shared/src/main/scala/zio/ZIO.scala @@ -1466,6 +1466,21 @@ sealed trait ZIO[-R, +E, +A] extends Serializable with ZIOPlatformSpecific[R, E, final def raceFirst[R1 <: R, E1 >: E, A1 >: A](that: ZIO[R1, E1, A1]): ZIO[R1, E1, A1] = (self.run race that.run).flatMap(ZIO.done(_)).refailWithTrace + /** + * Returns an effect that races this effect with all the specified effects, + * yielding the first result to complete, whether by success or failure. If + * neither effect completes, then the composed effect will not complete. + * + * WARNING: The raced effect will safely interrupt the "losers", but will not + * resume until the losers has been cleanly terminated. If early return is + * desired, then instead of performing `l raceAllFirst rs`, perform + * `l.disconnect raceAllFirst rs.flatMap(_.disconnect)`, which disconnects + * left and rights interrupt signal, allowing a fast return, with interruption + * performed in the background. + */ + final def raceAllFirst[R1 <: R, E1 >: E, A1 >: A](ios: Iterable[ZIO[R1, E1, A1]]): ZIO[R1, E1, A1] = + (self.run raceAll ios.map(_.run)).flatMap(ZIO.done(_)).refailWithTrace + /** * Returns an effect that races this effect with the specified effect, * yielding the first result to succeed. If neither effect succeeds, then the From b90c9b9b3491e31600a2f2471f8856a62ab39334 Mon Sep 17 00:00:00 2001 From: Ciprian Sofronia Date: Fri, 4 Mar 2022 18:39:44 +0200 Subject: [PATCH 2/4] Update docs --- core/shared/src/main/scala/zio/ZIO.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/shared/src/main/scala/zio/ZIO.scala b/core/shared/src/main/scala/zio/ZIO.scala index 6748d0fbd370..a1bc0775ae95 100644 --- a/core/shared/src/main/scala/zio/ZIO.scala +++ b/core/shared/src/main/scala/zio/ZIO.scala @@ -1474,7 +1474,7 @@ sealed trait ZIO[-R, +E, +A] extends Serializable with ZIOPlatformSpecific[R, E, * WARNING: The raced effect will safely interrupt the "losers", but will not * resume until the losers has been cleanly terminated. If early return is * desired, then instead of performing `l raceAllFirst rs`, perform - * `l.disconnect raceAllFirst rs.flatMap(_.disconnect)`, which disconnects + * `l.disconnect raceAllFirst rs.map(_.disconnect)`, which disconnects * left and rights interrupt signal, allowing a fast return, with interruption * performed in the background. */ From 6b2548583209d3a76be8948b9befc5e16335bc2a Mon Sep 17 00:00:00 2001 From: Ciprian Sofronia Date: Fri, 4 Mar 2022 19:02:18 +0200 Subject: [PATCH 3/4] Move raceFirst to ZIO companion --- .../shared/src/test/scala/zio/ZIOSpec.scala | 4 +-- core/shared/src/main/scala/zio/ZIO.scala | 30 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core-tests/shared/src/test/scala/zio/ZIOSpec.scala b/core-tests/shared/src/test/scala/zio/ZIOSpec.scala index 06f82bf85d96..3c66219b9c18 100644 --- a/core-tests/shared/src/test/scala/zio/ZIOSpec.scala +++ b/core-tests/shared/src/test/scala/zio/ZIOSpec.scala @@ -2677,7 +2677,7 @@ object ZIOSpec extends ZIOBaseSpec { effect <- Promise.make[Nothing, Int] winner = s.await *> IO.fromEither(Right(())) losers = List(ZIO.bracket(s.succeed(()))(_ => effect.succeed(42))(_ => ZIO.infinity)) - race = winner raceAllFirst losers + race = ZIO.raceFirst(winner, losers) _ <- race b <- effect.await } yield assert(b)(equalTo(42)) @@ -2688,7 +2688,7 @@ object ZIOSpec extends ZIOBaseSpec { effect <- Promise.make[Nothing, Int] winner = s.await *> IO.fromEither(Left(new Exception)) losers = List(ZIO.bracket(s.succeed(()))(_ => effect.succeed(42))(_ => ZIO.infinity)) - race = winner raceAllFirst losers + race = ZIO.raceFirst(winner, losers) _ <- race.either b <- effect.await } yield assert(b)(equalTo(42)) diff --git a/core/shared/src/main/scala/zio/ZIO.scala b/core/shared/src/main/scala/zio/ZIO.scala index a1bc0775ae95..f87da9d95408 100644 --- a/core/shared/src/main/scala/zio/ZIO.scala +++ b/core/shared/src/main/scala/zio/ZIO.scala @@ -1466,21 +1466,6 @@ sealed trait ZIO[-R, +E, +A] extends Serializable with ZIOPlatformSpecific[R, E, final def raceFirst[R1 <: R, E1 >: E, A1 >: A](that: ZIO[R1, E1, A1]): ZIO[R1, E1, A1] = (self.run race that.run).flatMap(ZIO.done(_)).refailWithTrace - /** - * Returns an effect that races this effect with all the specified effects, - * yielding the first result to complete, whether by success or failure. If - * neither effect completes, then the composed effect will not complete. - * - * WARNING: The raced effect will safely interrupt the "losers", but will not - * resume until the losers has been cleanly terminated. If early return is - * desired, then instead of performing `l raceAllFirst rs`, perform - * `l.disconnect raceAllFirst rs.map(_.disconnect)`, which disconnects - * left and rights interrupt signal, allowing a fast return, with interruption - * performed in the background. - */ - final def raceAllFirst[R1 <: R, E1 >: E, A1 >: A](ios: Iterable[ZIO[R1, E1, A1]]): ZIO[R1, E1, A1] = - (self.run raceAll ios.map(_.run)).flatMap(ZIO.done(_)).refailWithTrace - /** * Returns an effect that races this effect with the specified effect, * yielding the first result to succeed. If neither effect succeeds, then the @@ -3899,6 +3884,21 @@ object ZIO extends ZIOCompanionPlatformSpecific { ): ZIO[R1, E, A] = zio.raceAll(ios) + /** + * Returns an effect that races this effect with all the specified effects, + * yielding the first result to complete, whether by success or failure. If + * neither effect completes, then the composed effect will not complete. + * + * WARNING: The raced effect will safely interrupt the "losers", but will not + * resume until the losers has been cleanly terminated. If early return is + * desired, then instead of performing `l raceAllFirst rs`, perform + * `l.disconnect raceAllFirst rs.map(_.disconnect)`, which disconnects left + * and rights interrupt signal, allowing a fast return, with interruption + * performed in the background. + */ + def raceFirst[R, R1 <: R, E, A](zio: ZIO[R, E, A], ios: Iterable[ZIO[R1, E, A]]): ZIO[R1, E, A] = + (zio.run raceAll ios.map(_.run)).flatMap(ZIO.done(_)).refailWithTrace + /** * Reduces an `Iterable[IO]` to a single `IO`, working sequentially. */ From 9249fbd7d70d117e1073239d7c0aba1a38cd0767 Mon Sep 17 00:00:00 2001 From: Ciprian Sofronia Date: Fri, 4 Mar 2022 19:07:28 +0200 Subject: [PATCH 4/4] Update doc --- core/shared/src/main/scala/zio/ZIO.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/shared/src/main/scala/zio/ZIO.scala b/core/shared/src/main/scala/zio/ZIO.scala index f87da9d95408..532e0797eca8 100644 --- a/core/shared/src/main/scala/zio/ZIO.scala +++ b/core/shared/src/main/scala/zio/ZIO.scala @@ -3890,9 +3890,9 @@ object ZIO extends ZIOCompanionPlatformSpecific { * neither effect completes, then the composed effect will not complete. * * WARNING: The raced effect will safely interrupt the "losers", but will not - * resume until the losers has been cleanly terminated. If early return is - * desired, then instead of performing `l raceAllFirst rs`, perform - * `l.disconnect raceAllFirst rs.map(_.disconnect)`, which disconnects left + * resume until the losers have been cleanly terminated. If early return is + * desired, then instead of performing `ZIO.raceFirst(l, rs)`, perform + * `ZIO.raceFirst(l.disconnect, rs.map(_.disconnect))`, which disconnects left * and rights interrupt signal, allowing a fast return, with interruption * performed in the background. */