From e7428549e40903f36baf0e489ca7d85d784e3324 Mon Sep 17 00:00:00 2001 From: "Dr. Carsten Leue" Date: Fri, 12 Jan 2024 13:20:50 +0100 Subject: [PATCH] fix: add consistent Delay and After functions to IO Signed-off-by: Dr. Carsten Leue --- io/generic/io.go | 23 +++++++++++++++++++++++ io/io.go | 10 ++++++++++ ioeither/generic/ioeither.go | 7 ++++++- ioeither/ioeither.go | 12 ++++++++++++ iooption/generic/iooption.go | 5 +++++ iooption/iooption.go | 12 ++++++++++++ 6 files changed, 68 insertions(+), 1 deletion(-) diff --git a/io/generic/io.go b/io/generic/io.go index 71a0d68..e5a8612 100644 --- a/io/generic/io.go +++ b/io/generic/io.go @@ -133,6 +133,29 @@ func Delay[GA ~func() A, A any](delay time.Duration) func(GA) GA { } } +func after(timestamp time.Time) func() { + return func() { + // check if we need to wait + current := time.Now() + if current.Before(timestamp) { + time.Sleep(timestamp.Sub(current)) + } + } +} + +// After creates an operation that passes after the given timestamp +func After[GA ~func() A, A any](timestamp time.Time) func(GA) GA { + aft := after(timestamp) + return func(ga GA) GA { + return MakeIO[GA](func() A { + // wait as long as necessary + aft() + // execute after wait + return ga() + }) + } +} + // Now returns the current timestamp func Now[GA ~func() time.Time]() GA { return MakeIO[GA](time.Now) diff --git a/io/io.go b/io/io.go index a8dd08f..6513239 100644 --- a/io/io.go +++ b/io/io.go @@ -146,3 +146,13 @@ func MonadFlap[B, A any](fab IO[func(A) B], a A) IO[B] { func Flap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](a A) func(IO[func(A) B]) IO[B] { return G.Flap[func(A) B, IO[func(A) B], IO[B], A, B](a) } + +// Delay creates an operation that passes in the value after some delay +func Delay[A any](delay time.Duration) func(IO[A]) IO[A] { + return G.Delay[IO[A]](delay) +} + +// After creates an operation that passes after the given timestamp +func After[A any](timestamp time.Time) func(IO[A]) IO[A] { + return G.After[IO[A]](timestamp) +} diff --git a/ioeither/generic/ioeither.go b/ioeither/generic/ioeither.go index 690b1e7..f5c2f61 100644 --- a/ioeither/generic/ioeither.go +++ b/ioeither/generic/ioeither.go @@ -207,11 +207,16 @@ func MapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2, return F.Bind2nd(MonadMapLeft[GA1, GA2, E1, E2, A], f) } -// Delay creates an operation that passes in the value after some delay +// Delay creates an operation that passes in the value after some [time.Duration] func Delay[GA ~func() ET.Either[E, A], E, A any](delay time.Duration) func(GA) GA { return IO.Delay[GA](delay) } +// After creates an operation that passes after the given [time.Time] +func After[GA ~func() ET.Either[E, A], E, A any](timestamp time.Time) func(GA) GA { + return IO.After[GA](timestamp) +} + func MonadBiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2, A, B any](fa GA, f func(E1) E2, g func(A) B) GB { return eithert.MonadBiMap(IO.MonadMap[GA, GB, ET.Either[E1, A], ET.Either[E2, B]], fa, f, g) } diff --git a/ioeither/ioeither.go b/ioeither/ioeither.go index 67b6a52..c8e24ce 100644 --- a/ioeither/ioeither.go +++ b/ioeither/ioeither.go @@ -16,6 +16,8 @@ package ioeither import ( + "time" + ET "github.com/IBM/fp-go/either" I "github.com/IBM/fp-go/io" G "github.com/IBM/fp-go/ioeither/generic" @@ -276,3 +278,13 @@ func Flap[E, B, A any](a A) func(IOEither[E, func(A) B]) IOEither[E, B] { func ToIOOption[E, A any](ioe IOEither[E, A]) IOO.IOOption[A] { return G.ToIOOption[IOO.IOOption[A]](ioe) } + +// Delay creates an operation that passes in the value after some delay +func Delay[E, A any](delay time.Duration) func(IOEither[E, A]) IOEither[E, A] { + return G.Delay[IOEither[E, A]](delay) +} + +// After creates an operation that passes after the given [time.Time] +func After[E, A any](timestamp time.Time) func(IOEither[E, A]) IOEither[E, A] { + return G.After[IOEither[E, A]](timestamp) +} diff --git a/iooption/generic/iooption.go b/iooption/generic/iooption.go index f9e1cc0..3d9f678 100644 --- a/iooption/generic/iooption.go +++ b/iooption/generic/iooption.go @@ -219,6 +219,11 @@ func Delay[GA ~func() O.Option[A], A any](delay time.Duration) func(GA) GA { return IO.Delay[GA](delay) } +// After creates an operation that passes after the given [time.Time] +func After[GA ~func() O.Option[A], A any](timestamp time.Time) func(GA) GA { + return IO.After[GA](timestamp) +} + // Fold convers an IOOption into an IO func Fold[GA ~func() O.Option[A], GB ~func() B, A, B any](onNone func() GB, onSome func(A) GB) func(GA) GB { return optiont.MatchE(IO.MonadChain[GA, GB, O.Option[A], B], onNone, onSome) diff --git a/iooption/iooption.go b/iooption/iooption.go index 689f77c..e278716 100644 --- a/iooption/iooption.go +++ b/iooption/iooption.go @@ -16,6 +16,8 @@ package iooption import ( + "time" + ET "github.com/IBM/fp-go/either" I "github.com/IBM/fp-go/io" IO "github.com/IBM/fp-go/io" @@ -164,3 +166,13 @@ func MonadChainFirstIOK[A, B any](first IOOption[A], f func(A) IO.IO[B]) IOOptio func ChainFirstIOK[A, B any](f func(A) IO.IO[B]) func(IOOption[A]) IOOption[A] { return G.ChainFirstIOK[IOOption[A], IO.IO[B]](f) } + +// Delay creates an operation that passes in the value after some delay +func Delay[A any](delay time.Duration) func(IOOption[A]) IOOption[A] { + return G.Delay[IOOption[A]](delay) +} + +// After creates an operation that passes after the given [time.Time] +func After[A any](timestamp time.Time) func(IOOption[A]) IOOption[A] { + return G.After[IOOption[A]](timestamp) +}