(patch) add byte utilities to rng #2
2 changed files with 90 additions and 0 deletions
|
|
@ -24,6 +24,19 @@ object ByteCount:
|
||||||
*/
|
*/
|
||||||
final val OneGigabyte: ByteCount = 1000000000
|
final val OneGigabyte: ByteCount = 1000000000
|
||||||
|
|
||||||
|
/** Provide integer representations for common sizes in terms of number of
|
||||||
|
* bytes. These values are useful for things like array sizing that depend on
|
||||||
|
* the `Int` type.
|
||||||
|
*/
|
||||||
|
object IntSizes:
|
||||||
|
|
||||||
|
final val Zero: Int = 0
|
||||||
|
final val OneKilobyte: Int = 1000
|
||||||
|
final val OneMegabyte: Int = 1000000
|
||||||
|
final val OneGigabyte: Int = 1000000000
|
||||||
|
|
||||||
|
end IntSizes
|
||||||
|
|
||||||
/** Express the given number as a byte count. All values are normalized to the
|
/** Express the given number as a byte count. All values are normalized to the
|
||||||
* absolute value -- negative values are coerced to positive.
|
* absolute value -- negative values are coerced to positive.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ package gs.std.v0.effect
|
||||||
import cats.Applicative
|
import cats.Applicative
|
||||||
import cats.effect.Sync
|
import cats.effect.Sync
|
||||||
import cats.syntax.all.*
|
import cats.syntax.all.*
|
||||||
|
import fs2.Chunk
|
||||||
import fs2.Stream
|
import fs2.Stream
|
||||||
|
import gs.std.v0.core.Blob
|
||||||
|
import gs.std.v0.core.ByteCount
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.util.Random
|
import java.util.Random
|
||||||
|
|
||||||
|
|
@ -154,6 +157,29 @@ trait Rng[F[_]]:
|
||||||
bound: Double
|
bound: Double
|
||||||
): Stream[F, Double]
|
): Stream[F, Double]
|
||||||
|
|
||||||
|
/** Produce an array of random bytes.
|
||||||
|
*
|
||||||
|
* @param count
|
||||||
|
* The number of bytes to produce.
|
||||||
|
* @return
|
||||||
|
* The array of randomly generated bytes.
|
||||||
|
*/
|
||||||
|
def nextByteArray(count: Int): F[Array[Byte]]
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
* Infinite stream of random bytes.
|
||||||
|
*/
|
||||||
|
def nextBytes(): Stream[F, Byte]
|
||||||
|
|
||||||
|
/** Produce a blob of random bytes.
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* The number of bytes to produce.
|
||||||
|
* @return
|
||||||
|
* The blob of randomly generated bytes.
|
||||||
|
*/
|
||||||
|
def nextBlob(size: Int): F[Blob]
|
||||||
|
|
||||||
object Rng:
|
object Rng:
|
||||||
|
|
||||||
/** Instantiate [[Rng]] using a new `java.util.Random` instance.
|
/** Instantiate [[Rng]] using a new `java.util.Random` instance.
|
||||||
|
|
@ -212,6 +238,42 @@ object Rng:
|
||||||
*/
|
*/
|
||||||
final class JavaRandom[F[_]: Sync](random: Random) extends Rng[F]:
|
final class JavaRandom[F[_]: Sync](random: Random) extends Rng[F]:
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
override def nextBytes(): Stream[F, Byte] =
|
||||||
|
Stream
|
||||||
|
.evalUnChunk[F, Byte](Sync[F].delay {
|
||||||
|
// Allocate space for the random data. Generate 1kb at once.
|
||||||
|
val bytes = new Array[Byte](ByteCount.IntSizes.OneKilobyte)
|
||||||
|
val _ = random.nextBytes(bytes)
|
||||||
|
// This chunk is _backed by_ the array -- the data isn't copied, so we
|
||||||
|
// allocate a new array each time and cede it to the chunk.
|
||||||
|
Chunk.array(bytes)
|
||||||
|
})
|
||||||
|
.repeat
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
override def nextByteArray(count: Int): F[Array[Byte]] =
|
||||||
|
if count < 0 then
|
||||||
|
Sync[F].raiseError(
|
||||||
|
new IllegalArgumentException(
|
||||||
|
"Cannot generate a negative number of bytes."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else if count == 0 then Sync[F].pure(Array.empty)
|
||||||
|
else
|
||||||
|
Sync[F].delay {
|
||||||
|
val bytes = new Array[Byte](count)
|
||||||
|
val _ = random.nextBytes(bytes)
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
override def nextBlob(size: Int): F[Blob] =
|
||||||
|
nextByteArray(size).map(new Blob(_))
|
||||||
|
|
||||||
/** @inheritDocs
|
/** @inheritDocs
|
||||||
*/
|
*/
|
||||||
override def updateSeed(seed: Long): F[Rng[F]] =
|
override def updateSeed(seed: Long): F[Rng[F]] =
|
||||||
|
|
@ -306,6 +368,21 @@ object Rng:
|
||||||
*/
|
*/
|
||||||
final class Zero[F[_]: Applicative] extends Rng[F]:
|
final class Zero[F[_]: Applicative] extends Rng[F]:
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
override def nextByteArray(count: Int): F[Array[Byte]] =
|
||||||
|
Applicative[F].pure(Array.fill[Byte](count)(0))
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
override def nextBytes(): Stream[F, Byte] =
|
||||||
|
Stream[F, Byte](0).repeat
|
||||||
|
|
||||||
|
/** @inheritDocs
|
||||||
|
*/
|
||||||
|
override def nextBlob(size: Int): F[Blob] =
|
||||||
|
nextByteArray(size).map(new Blob(_))
|
||||||
|
|
||||||
/** @inheritDocs
|
/** @inheritDocs
|
||||||
*/
|
*/
|
||||||
override def updateSeed(seed: Long): F[Rng[F]] = Applicative[F].pure(this)
|
override def updateSeed(seed: Long): F[Rng[F]] = Applicative[F].pure(this)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue