From 7981ff49e83c5e37fc99c24e312e5ae17bddb1a4 Mon Sep 17 00:00:00 2001 From: patseev Date: Thu, 11 Feb 2021 22:44:57 +0300 Subject: [PATCH 1/3] feat: timed syntax for GenTemporal --- core/shared/src/main/scala/cats/effect/IO.scala | 3 +++ .../src/main/scala/cats/effect/kernel/GenTemporal.scala | 7 +++++++ .../cats/effect/kernel/syntax/GenTemporalSyntax.scala | 3 +++ .../src/test/scala/cats/effect/kernel/SyntaxSpec.scala | 5 +++++ 4 files changed, 18 insertions(+) diff --git a/core/shared/src/main/scala/cats/effect/IO.scala b/core/shared/src/main/scala/cats/effect/IO.scala index d72d7ee085..b678c74010 100644 --- a/core/shared/src/main/scala/cats/effect/IO.scala +++ b/core/shared/src/main/scala/cats/effect/IO.scala @@ -159,6 +159,9 @@ sealed abstract class IO[+A] private () extends IOPlatform[A] { case Left(value) => IO.pure(value) } + def timed: IO[(FiniteDuration, A)] = + GenTemporal[IO].timed(this) + def product[B](that: IO[B]): IO[(A, B)] = flatMap(a => that.map(b => (a, b))) diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/GenTemporal.scala b/kernel/shared/src/main/scala/cats/effect/kernel/GenTemporal.scala index 56715bc94b..e2d522a502 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/GenTemporal.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/GenTemporal.scala @@ -72,6 +72,13 @@ trait GenTemporal[F[_], E] extends GenConcurrent[F, E] with Clock[F] { timeoutTo(fa, duration, timeoutException) } + /** + * Returns an effect that completes with the result of the source together + * with the duration that it took to complete. + */ + def timed[A](fa: F[A]): F[(FiniteDuration, A)] = + map3(realTime, fa, realTime)((startTime, a, endTime) => (endTime.minus(startTime), a)) + } object GenTemporal { diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenTemporalSyntax.scala b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenTemporalSyntax.scala index 6a2e6d2df5..d27cbe2bc8 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenTemporalSyntax.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenTemporalSyntax.scala @@ -47,6 +47,9 @@ final class GenTemporalOps_[F[_], A] private[syntax] (private val wrapped: F[A]) def andWait(time: FiniteDuration)(implicit F: GenTemporal[F, _]): F[A] = F.andWait(wrapped, time) + + def timed(implicit F: GenTemporal[F, _]): F[(FiniteDuration, A)] = + F.timed(wrapped) } final class GenTemporalOps[F[_], A, E] private[syntax] (private val wrapped: F[A]) 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 04377f87b5..ae19055fcf 100644 --- a/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala +++ b/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala @@ -162,6 +162,11 @@ class SyntaxSpec extends Specification { val result = target.andWait(param) result: F[A] } + + { + val result = target.timed + result: F[(FiniteDuration, A)] + } } def temporalSyntax[F[_], A](target: F[A])(implicit F: Temporal[F]) = { From 769545b7598d2314dde0369b8daf0cb2ecf1392a Mon Sep 17 00:00:00 2001 From: patseev Date: Fri, 12 Feb 2021 00:14:56 +0300 Subject: [PATCH 2/3] move 'timed' to Clock from GenTemporal --- .../src/main/scala/cats/effect/IO.scala | 2 +- .../scala/cats/effect/syntax/package.scala | 1 + .../main/scala/cats/effect/kernel/Clock.scala | 8 +++++ .../cats/effect/kernel/GenTemporal.scala | 8 ----- .../cats/effect/kernel/syntax/AllSyntax.scala | 1 + .../effect/kernel/syntax/ClockSyntax.scala | 32 +++++++++++++++++++ .../kernel/syntax/GenTemporalSyntax.scala | 3 -- .../cats/effect/kernel/syntax/package.scala | 1 + .../scala/cats/effect/kernel/SyntaxSpec.scala | 16 +++++++--- 9 files changed, 55 insertions(+), 17 deletions(-) create mode 100644 kernel/shared/src/main/scala/cats/effect/kernel/syntax/ClockSyntax.scala diff --git a/core/shared/src/main/scala/cats/effect/IO.scala b/core/shared/src/main/scala/cats/effect/IO.scala index b678c74010..f0a10a3dc5 100644 --- a/core/shared/src/main/scala/cats/effect/IO.scala +++ b/core/shared/src/main/scala/cats/effect/IO.scala @@ -160,7 +160,7 @@ sealed abstract class IO[+A] private () extends IOPlatform[A] { } def timed: IO[(FiniteDuration, A)] = - GenTemporal[IO].timed(this) + Clock[IO].timed(this) def product[B](that: IO[B]): IO[(A, B)] = flatMap(a => that.map(b => (a, b))) diff --git a/core/shared/src/main/scala/cats/effect/syntax/package.scala b/core/shared/src/main/scala/cats/effect/syntax/package.scala index f002d2229e..1ea36a2f32 100644 --- a/core/shared/src/main/scala/cats/effect/syntax/package.scala +++ b/core/shared/src/main/scala/cats/effect/syntax/package.scala @@ -26,4 +26,5 @@ package object syntax { object temporal extends kernel.syntax.GenTemporalSyntax object async extends kernel.syntax.AsyncSyntax object resource extends kernel.syntax.ResourceSyntax + object clock extends kernel.syntax.ClockSyntax } diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/Clock.scala b/kernel/shared/src/main/scala/cats/effect/kernel/Clock.scala index a6c3b635ff..58f4fe1a69 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/Clock.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/Clock.scala @@ -33,6 +33,14 @@ trait Clock[F[_]] extends ClockPlatform[F] { // lawless (unfortunately), but meant to represent current (when sequenced) system time def realTime: F[FiniteDuration] + + /** + * Returns an effect that completes with the result of the source together + * with the duration that it took to complete. + */ + def timed[A](fa: F[A]): F[(FiniteDuration, A)] = + applicative.map3(monotonic, fa, monotonic)((startTime, a, endTime) => + (endTime.minus(startTime), a)) } object Clock { diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/GenTemporal.scala b/kernel/shared/src/main/scala/cats/effect/kernel/GenTemporal.scala index e2d522a502..95bcc56001 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/GenTemporal.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/GenTemporal.scala @@ -71,14 +71,6 @@ trait GenTemporal[F[_], E] extends GenConcurrent[F, E] with Clock[F] { val timeoutException = raiseError[A](ev(new TimeoutException(duration.toString))) timeoutTo(fa, duration, timeoutException) } - - /** - * Returns an effect that completes with the result of the source together - * with the duration that it took to complete. - */ - def timed[A](fa: F[A]): F[(FiniteDuration, A)] = - map3(realTime, fa, realTime)((startTime, a, endTime) => (endTime.minus(startTime), a)) - } object GenTemporal { diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/AllSyntax.scala b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/AllSyntax.scala index 7f5cb76f44..199b81f966 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/AllSyntax.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/AllSyntax.scala @@ -23,3 +23,4 @@ trait AllSyntax with GenConcurrentSyntax with AsyncSyntax with ResourceSyntax + with ClockSyntax diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/ClockSyntax.scala b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/ClockSyntax.scala new file mode 100644 index 0000000000..67155764a1 --- /dev/null +++ b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/ClockSyntax.scala @@ -0,0 +1,32 @@ +/* + * Copyright 2020-2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cats.effect.kernel.syntax + +import cats.effect.kernel.Clock + +import scala.concurrent.duration.FiniteDuration + +trait ClockSyntax { + implicit def clockOps[F[_], A, E](wrapped: F[A]): ClockOps[F, A] = + new ClockOps(wrapped) +} + +final class ClockOps[F[_], A] private[syntax] (private val wrapped: F[A]) extends AnyVal { + + def timed(implicit F: Clock[F]): F[(FiniteDuration, A)] = + F.timed(wrapped) +} diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenTemporalSyntax.scala b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenTemporalSyntax.scala index d27cbe2bc8..6a2e6d2df5 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenTemporalSyntax.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/GenTemporalSyntax.scala @@ -47,9 +47,6 @@ final class GenTemporalOps_[F[_], A] private[syntax] (private val wrapped: F[A]) def andWait(time: FiniteDuration)(implicit F: GenTemporal[F, _]): F[A] = F.andWait(wrapped, time) - - def timed(implicit F: GenTemporal[F, _]): F[(FiniteDuration, A)] = - F.timed(wrapped) } final class GenTemporalOps[F[_], A, E] private[syntax] (private val wrapped: F[A]) diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/package.scala b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/package.scala index 5d40bb0844..9de009ed7d 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/package.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/package.scala @@ -26,4 +26,5 @@ package object syntax { object temporal extends GenTemporalSyntax object async extends AsyncSyntax object resource extends ResourceSyntax + object clock extends ClockSyntax } 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 ae19055fcf..bcde3f6507 100644 --- a/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala +++ b/kernel/shared/src/test/scala/cats/effect/kernel/SyntaxSpec.scala @@ -162,11 +162,6 @@ class SyntaxSpec extends Specification { val result = target.andWait(param) result: F[A] } - - { - val result = target.timed - result: F[(FiniteDuration, A)] - } } def temporalSyntax[F[_], A](target: F[A])(implicit F: Temporal[F]) = { @@ -200,4 +195,15 @@ class SyntaxSpec extends Specification { result: Resource[F, A] } } + + def clockSyntax[F[_], A](target: F[A])(implicit F: Clock[F]) = { + import syntax.clock._ + + Clock[F]: F.type + + { + val result = target.timed + result: F[(FiniteDuration, A)] + } + } } From 34cf98d01a9f0faa4f4117e4fa7160747dc3df68 Mon Sep 17 00:00:00 2001 From: Andrey Patseev <25015145+patseev@users.noreply.github.com> Date: Fri, 12 Feb 2021 14:39:26 +0300 Subject: [PATCH 3/3] remove unused type parameter Co-authored-by: Georgi Krastev --- .../src/main/scala/cats/effect/kernel/syntax/ClockSyntax.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/ClockSyntax.scala b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/ClockSyntax.scala index 67155764a1..155abbc989 100644 --- a/kernel/shared/src/main/scala/cats/effect/kernel/syntax/ClockSyntax.scala +++ b/kernel/shared/src/main/scala/cats/effect/kernel/syntax/ClockSyntax.scala @@ -21,7 +21,7 @@ import cats.effect.kernel.Clock import scala.concurrent.duration.FiniteDuration trait ClockSyntax { - implicit def clockOps[F[_], A, E](wrapped: F[A]): ClockOps[F, A] = + implicit def clockOps[F[_], A](wrapped: F[A]): ClockOps[F, A] = new ClockOps(wrapped) }