Adding and improving effect implementations.
All checks were successful
/ Build and Release Library (push) Successful in 1m31s
All checks were successful
/ Build and Release Library (push) Successful in 1m31s
This commit is contained in:
parent
eedf6e8f04
commit
479a9f6753
4 changed files with 519 additions and 168 deletions
|
|
@ -0,0 +1,87 @@
|
|||
package gs.std.v0.effect
|
||||
|
||||
import cats.effect.Sync
|
||||
import cats.syntax.all.*
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.ZoneId
|
||||
|
||||
/** Implementation of [[DateTimeProvider]] based on a specific
|
||||
* `java.time.Clock`. All dates and times are calculated using this clock.
|
||||
*
|
||||
* @param clock
|
||||
* The clock used to calculate dates and times.
|
||||
*/
|
||||
final class ClockDateTimeProvider[F[_]: Sync](
|
||||
val clock: Clock
|
||||
) extends DateTimeProvider[F]:
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def timestamp(): F[Instant] =
|
||||
Sync[F].delay(Instant.now(clock))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nowInstant(): F[Instant] =
|
||||
Sync[F].delay(Instant.now(clock))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nowZoned(): F[ZonedDateTime] =
|
||||
Sync[F].delay(ZonedDateTime.now(clock))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nowOffset(): F[OffsetDateTime] =
|
||||
Sync[F].delay(OffsetDateTime.now(clock))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def today(): F[LocalDate] =
|
||||
Sync[F].delay(LocalDate.now(clock))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def yesterday(): F[LocalDate] =
|
||||
today().map(_.minusDays(1L))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def tomorrow(): F[LocalDate] =
|
||||
today().map(_.plusDays(1L))
|
||||
|
||||
object ClockDateTimeProvider:
|
||||
|
||||
/** Instantiate a new [[ClockDateTimeProvider]].
|
||||
*
|
||||
* @param clock
|
||||
* The clock to use for all date/time calculations.
|
||||
* @return
|
||||
* The new [[DateTimeProvider]] instance.
|
||||
*/
|
||||
def apply[F[_]: Sync](clock: Clock): DateTimeProvider[F] =
|
||||
new ClockDateTimeProvider[F](clock)
|
||||
|
||||
/** @return
|
||||
* A new [[ClockDateTimeProvider]] based on the system's default zone using
|
||||
* the system's clock.
|
||||
*/
|
||||
def system[F[_]: Sync]: DateTimeProvider[F] =
|
||||
new ClockDateTimeProvider[F](Clock.systemDefaultZone())
|
||||
|
||||
/** Use a system clock aligned to the given zone.
|
||||
*
|
||||
* @param zoneId
|
||||
* The identifier of the zone to target.
|
||||
* @return
|
||||
* A new [[ClockDateTimeProvider]] based on the specified zone using the
|
||||
* system's clock.
|
||||
*/
|
||||
def forZone[F[_]: Sync](zoneId: ZoneId): DateTimeProvider[F] =
|
||||
new ClockDateTimeProvider[F](Clock.system(zoneId))
|
||||
|
||||
end ClockDateTimeProvider
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package gs.std.v0.effect
|
||||
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
/** Provides date and time values.
|
||||
*/
|
||||
trait DateTimeProvider[F[_]]:
|
||||
/** @return
|
||||
* The current timestamp (`java.time.Instant`).
|
||||
*/
|
||||
def timestamp(): F[Instant]
|
||||
|
||||
/** @return
|
||||
* The current `java.time.Instant`.
|
||||
*/
|
||||
def nowInstant(): F[Instant]
|
||||
|
||||
/** @return
|
||||
* The current date and time in the configured zone.
|
||||
*/
|
||||
def nowZoned(): F[ZonedDateTime]
|
||||
|
||||
/** @return
|
||||
* The current date and time in the configured offset.
|
||||
*/
|
||||
def nowOffset(): F[OffsetDateTime]
|
||||
|
||||
/** @return
|
||||
* The current date.
|
||||
*/
|
||||
def today(): F[LocalDate]
|
||||
|
||||
/** @return
|
||||
* The date before today.
|
||||
*/
|
||||
def yesterday(): F[LocalDate]
|
||||
|
||||
/** @return
|
||||
* The date after today.
|
||||
*/
|
||||
def tomorrow(): F[LocalDate]
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
package gs.std.v0.effect
|
||||
|
||||
import cats.Applicative
|
||||
import cats.effect.Sync
|
||||
import fs2.Stream
|
||||
import java.security.SecureRandom
|
||||
import java.util.Random
|
||||
|
||||
trait RNG[F[_]]:
|
||||
def nextInt(): F[Int]
|
||||
def nextInt(bound: Int): F[Int]
|
||||
|
||||
def nextInt(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): F[Int]
|
||||
|
||||
def nextLong(): F[Long]
|
||||
def nextLong(bound: Long): F[Long]
|
||||
|
||||
def nextLong(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): F[Long]
|
||||
|
||||
def nextDouble(): F[Double]
|
||||
def nextDouble(bound: Double): F[Double]
|
||||
|
||||
def nextDouble(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): F[Double]
|
||||
|
||||
def nextBoolean(): F[Boolean]
|
||||
|
||||
def nextInts(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): Stream[F, Int]
|
||||
|
||||
def nextLongs(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): Stream[F, Long]
|
||||
|
||||
def nextDoubles(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): Stream[F, Double]
|
||||
|
||||
object RNG:
|
||||
|
||||
def secure[F[_]: Sync]: RNG[F] =
|
||||
new JavaRandom[F](new SecureRandom())
|
||||
|
||||
final class JavaRandom[F[_]: Sync](random: Random) extends RNG[F]:
|
||||
|
||||
override def nextInt(): F[Int] =
|
||||
Sync[F].delay(random.nextInt())
|
||||
|
||||
override def nextInt(bound: Int): F[Int] =
|
||||
Sync[F].delay(random.nextInt(bound))
|
||||
|
||||
override def nextInt(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): F[Int] =
|
||||
Sync[F].delay(random.nextInt(origin, bound))
|
||||
|
||||
override def nextLong(): F[Long] =
|
||||
Sync[F].delay(random.nextLong())
|
||||
|
||||
override def nextLong(bound: Long): F[Long] =
|
||||
Sync[F].delay(random.nextLong(bound))
|
||||
|
||||
override def nextLong(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): F[Long] =
|
||||
Sync[F].delay(random.nextLong(origin, bound))
|
||||
|
||||
override def nextDouble(): F[Double] =
|
||||
Sync[F].delay(random.nextDouble())
|
||||
|
||||
override def nextDouble(bound: Double): F[Double] =
|
||||
Sync[F].delay(random.nextDouble(bound))
|
||||
|
||||
override def nextDouble(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): F[Double] =
|
||||
Sync[F].delay(random.nextDouble(origin, bound))
|
||||
|
||||
override def nextBoolean(): F[Boolean] =
|
||||
Sync[F].delay(random.nextBoolean())
|
||||
|
||||
override def nextInts(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): Stream[F, Int] =
|
||||
Stream.repeatEval(nextInt(origin, bound))
|
||||
|
||||
override def nextLongs(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): Stream[F, Long] =
|
||||
Stream.repeatEval(nextLong(origin, bound))
|
||||
|
||||
override def nextDoubles(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): Stream[F, Double] =
|
||||
Stream.repeatEval(nextDouble(origin, bound))
|
||||
|
||||
end JavaRandom
|
||||
|
||||
final class Zero[F[_]: Applicative] extends RNG[F]:
|
||||
|
||||
override def nextInt(): F[Int] = Applicative[F].pure(0)
|
||||
|
||||
override def nextInt(bound: Int): F[Int] = Applicative[F].pure(0)
|
||||
|
||||
override def nextInt(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): F[Int] = Applicative[F].pure(0)
|
||||
|
||||
override def nextLong(): F[Long] = Applicative[F].pure(0)
|
||||
|
||||
override def nextLong(bound: Long): F[Long] = Applicative[F].pure(0)
|
||||
|
||||
override def nextLong(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): F[Long] = Applicative[F].pure(0)
|
||||
|
||||
override def nextDouble(): F[Double] = Applicative[F].pure(0.0)
|
||||
|
||||
override def nextDouble(bound: Double): F[Double] = Applicative[F].pure(0.0)
|
||||
|
||||
override def nextDouble(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): F[Double] = Applicative[F].pure(0.0)
|
||||
|
||||
override def nextBoolean(): F[Boolean] = Applicative[F].pure(false)
|
||||
|
||||
override def nextInts(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): Stream[F, Int] =
|
||||
Stream.repeatEval(Applicative[F].pure(0))
|
||||
|
||||
override def nextLongs(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): Stream[F, Long] =
|
||||
Stream.repeatEval(Applicative[F].pure(0))
|
||||
|
||||
override def nextDoubles(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): Stream[F, Double] =
|
||||
Stream.repeatEval(Applicative[F].pure(0.0))
|
||||
|
||||
end Zero
|
||||
|
||||
end RNG
|
||||
388
modules/effect/src/main/scala/src/gs/std/v0/effect/Rng.scala
Normal file
388
modules/effect/src/main/scala/src/gs/std/v0/effect/Rng.scala
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
package gs.std.v0.effect
|
||||
|
||||
import cats.Applicative
|
||||
import cats.effect.Sync
|
||||
import cats.syntax.all.*
|
||||
import fs2.Stream
|
||||
import java.security.SecureRandom
|
||||
import java.util.Random
|
||||
|
||||
/** Random number generator.
|
||||
*/
|
||||
trait Rng[F[_]]:
|
||||
|
||||
/** Explicitly set or update the seed using the given 8 bytes.
|
||||
*
|
||||
* @param seed
|
||||
* The seed value to assign or augment.
|
||||
* @return
|
||||
* This [[Rng]] instance.
|
||||
*/
|
||||
def updateSeed(seed: Long): F[Rng[F]]
|
||||
|
||||
/** @return
|
||||
* The next (unbounded) random `Int`.
|
||||
*/
|
||||
def nextInt(): F[Int]
|
||||
|
||||
/** Calculate a number bounded inclusively within 0 and some bound.
|
||||
*
|
||||
* @param bound
|
||||
* The bound.
|
||||
* @return
|
||||
* The calculated number.
|
||||
*/
|
||||
def nextInt(bound: Int): F[Int]
|
||||
|
||||
/** Calculate a number bounded inclusively within some origin and some bound.
|
||||
*
|
||||
* @param origin
|
||||
* The origin.
|
||||
* @param bound
|
||||
* The bound.
|
||||
* @return
|
||||
* The calculated number.
|
||||
*/
|
||||
def nextInt(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): F[Int]
|
||||
|
||||
/** @return
|
||||
* The next (unbounded) random `Long`.
|
||||
*/
|
||||
def nextLong(): F[Long]
|
||||
|
||||
/** Calculate a number bounded inclusively within 0 and some bound.
|
||||
*
|
||||
* @param bound
|
||||
* The bound.
|
||||
* @return
|
||||
* The calculated number.
|
||||
*/
|
||||
def nextLong(bound: Long): F[Long]
|
||||
|
||||
/** Calculate a number bounded inclusively within some origin and some bound.
|
||||
*
|
||||
* @param origin
|
||||
* The origin.
|
||||
* @param bound
|
||||
* The bound.
|
||||
* @return
|
||||
* The calculated number.
|
||||
*/
|
||||
def nextLong(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): F[Long]
|
||||
|
||||
/** @return
|
||||
* The next (unbounded) random `Double`.
|
||||
*/
|
||||
def nextDouble(): F[Double]
|
||||
|
||||
/** Calculate a number bounded inclusively within 0 and some bound.
|
||||
*
|
||||
* @param bound
|
||||
* The bound.
|
||||
* @return
|
||||
* The calculated number.
|
||||
*/
|
||||
def nextDouble(bound: Double): F[Double]
|
||||
|
||||
/** Calculate a number bounded inclusively within some origin and some bound.
|
||||
*
|
||||
* @param origin
|
||||
* The origin.
|
||||
* @param bound
|
||||
* The bound.
|
||||
* @return
|
||||
* The calculated number.
|
||||
*/
|
||||
def nextDouble(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): F[Double]
|
||||
|
||||
/** @return
|
||||
* The next randomly selected `true` or `false` value.
|
||||
*/
|
||||
def nextBoolean(): F[Boolean]
|
||||
|
||||
/** Produce an infinite stream of `Int` bounded inclusively within some origin
|
||||
* and some bound.
|
||||
*
|
||||
* @param origin
|
||||
* The origin.
|
||||
* @param bound
|
||||
* The bound.
|
||||
* @return
|
||||
* The infinite stream of values.
|
||||
*/
|
||||
def nextInts(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): Stream[F, Int]
|
||||
|
||||
/** Produce an infinite stream of `Long` bounded inclusively within some
|
||||
* origin and some bound.
|
||||
*
|
||||
* @param origin
|
||||
* The origin.
|
||||
* @param bound
|
||||
* The bound.
|
||||
* @return
|
||||
* The infinite stream of values.
|
||||
*/
|
||||
def nextLongs(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): Stream[F, Long]
|
||||
|
||||
/** Produce an infinite stream of `Double` bounded inclusively within some
|
||||
* origin and some bound.
|
||||
*
|
||||
* @param origin
|
||||
* The origin.
|
||||
* @param bound
|
||||
* The bound.
|
||||
* @return
|
||||
* The infinite stream of values.
|
||||
*/
|
||||
def nextDoubles(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): Stream[F, Double]
|
||||
|
||||
object Rng:
|
||||
|
||||
/** Instantiate [[Rng]] using a new `java.util.Random` instance.
|
||||
*
|
||||
* For secure random number generation, please refer to the `secure[F]`
|
||||
* function.
|
||||
*
|
||||
* @param random
|
||||
* The `java.util.Random` instance.
|
||||
* @return
|
||||
* The new [[Rng]].
|
||||
*/
|
||||
def default[F[_]: Sync]: Rng[F] =
|
||||
default[F](new Random())
|
||||
|
||||
/** Instantiate [[Rng]] using the given random number generator.
|
||||
*
|
||||
* @param random
|
||||
* The `java.util.Random` instance.
|
||||
* @return
|
||||
* The new [[Rng]].
|
||||
*/
|
||||
def default[F[_]: Sync](random: Random): Rng[F] =
|
||||
new JavaRandom[F](random)
|
||||
|
||||
/** Instantiate [[Rng]] using a new `java.security.SecureRandom` instance.
|
||||
*
|
||||
* @param random
|
||||
* The `java.security.SecureRandom` instance.
|
||||
* @return
|
||||
* The new [[Rng]].
|
||||
*/
|
||||
def secure[F[_]: Sync]: Rng[F] =
|
||||
secure[F](new SecureRandom())
|
||||
|
||||
/** Instantiate [[Rng]] using the given secure random number generator.
|
||||
*
|
||||
* @param random
|
||||
* The `java.security.SecureRandom` instance.
|
||||
* @return
|
||||
* The new [[Rng]].
|
||||
*/
|
||||
def secure[F[_]: Sync](random: SecureRandom): Rng[F] =
|
||||
new JavaRandom[F](random)
|
||||
|
||||
/** @return
|
||||
* New instance of [[Rng]] that always returns `0` or `false`.
|
||||
*/
|
||||
def zero[F[_]: Applicative]: Rng[F] =
|
||||
new Zero[F]
|
||||
|
||||
/** Implementation of [[Rng]] based on any given `java.util.Random` instance.
|
||||
*
|
||||
* @param random
|
||||
* The underlying random number generator.
|
||||
*/
|
||||
final class JavaRandom[F[_]: Sync](random: Random) extends Rng[F]:
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def updateSeed(seed: Long): F[Rng[F]] =
|
||||
Sync[F].delay(random.setSeed(seed)).as(this)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextInt(): F[Int] =
|
||||
Sync[F].delay(random.nextInt())
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextInt(bound: Int): F[Int] =
|
||||
Sync[F].delay(random.nextInt(bound))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextInt(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): F[Int] =
|
||||
Sync[F].delay(random.nextInt(origin, bound))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextLong(): F[Long] =
|
||||
Sync[F].delay(random.nextLong())
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextLong(bound: Long): F[Long] =
|
||||
Sync[F].delay(random.nextLong(bound))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextLong(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): F[Long] =
|
||||
Sync[F].delay(random.nextLong(origin, bound))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextDouble(): F[Double] =
|
||||
Sync[F].delay(random.nextDouble())
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextDouble(bound: Double): F[Double] =
|
||||
Sync[F].delay(random.nextDouble(bound))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextDouble(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): F[Double] =
|
||||
Sync[F].delay(random.nextDouble(origin, bound))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextBoolean(): F[Boolean] =
|
||||
Sync[F].delay(random.nextBoolean())
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextInts(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): Stream[F, Int] =
|
||||
Stream.repeatEval(nextInt(origin, bound))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextLongs(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): Stream[F, Long] =
|
||||
Stream.repeatEval(nextLong(origin, bound))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextDoubles(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): Stream[F, Double] =
|
||||
Stream.repeatEval(nextDouble(origin, bound))
|
||||
|
||||
end JavaRandom
|
||||
|
||||
/** Implementation of [[Rng]] that always returns `0` or `false`.
|
||||
*/
|
||||
final class Zero[F[_]: Applicative] extends Rng[F]:
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def updateSeed(seed: Long): F[Rng[F]] = Applicative[F].pure(this)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextInt(): F[Int] = Applicative[F].pure(0)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextInt(bound: Int): F[Int] = Applicative[F].pure(0)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextInt(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): F[Int] = Applicative[F].pure(0)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextLong(): F[Long] = Applicative[F].pure(0)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextLong(bound: Long): F[Long] = Applicative[F].pure(0)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextLong(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): F[Long] = Applicative[F].pure(0)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextDouble(): F[Double] = Applicative[F].pure(0.0)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextDouble(bound: Double): F[Double] = Applicative[F].pure(0.0)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextDouble(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): F[Double] = Applicative[F].pure(0.0)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextBoolean(): F[Boolean] = Applicative[F].pure(false)
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextInts(
|
||||
origin: Int,
|
||||
bound: Int
|
||||
): Stream[F, Int] =
|
||||
Stream.repeatEval(Applicative[F].pure(0))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextLongs(
|
||||
origin: Long,
|
||||
bound: Long
|
||||
): Stream[F, Long] =
|
||||
Stream.repeatEval(Applicative[F].pure(0))
|
||||
|
||||
/** @inheritDocs
|
||||
*/
|
||||
override def nextDoubles(
|
||||
origin: Double,
|
||||
bound: Double
|
||||
): Stream[F, Double] =
|
||||
Stream.repeatEval(Applicative[F].pure(0.0))
|
||||
|
||||
end Zero
|
||||
|
||||
end Rng
|
||||
Loading…
Add table
Reference in a new issue