diff --git a/random/README.mbt.md b/random/README.mbt.md index 10ed8cca3..ae96b6c70 100644 --- a/random/README.mbt.md +++ b/random/README.mbt.md @@ -8,7 +8,7 @@ Internally, it uses the `Chacha8` cipher to generate random numbers. It is a cry ```moonbit test { - let r = @random.new() + let r = @random.Rand::new(@random.chacha8()) assert_eq!(r.uint(limit=10), 7) assert_eq!(r.uint(limit=10), 0) assert_eq!(r.uint(limit=10), 5) diff --git a/random/random.mbt b/random/random.mbt index c7a317bd2..6b3f4dd33 100644 --- a/random/random.mbt +++ b/random/random.mbt @@ -13,36 +13,57 @@ // limitations under the License. ///| -/// Currently we only support [chacha8] as the source of randomness. -struct Rand { - src : @random_source.ChaCha8 +/// `Rand` is a pseudo-random number generator (PRNG) that provides various +/// methods to generate random numbers of different types. +type Rand &Source + +///| +/// The [Source] trait defines a method to generate random numbers. +pub(open) trait Source { + next(Self) -> UInt64 +} + +///| +impl Source for @random_source.ChaCha8 with next(self : @random_source.ChaCha8) -> UInt64 { + for { + let x = self.state.next() + if x.1 { + return x.0 + } + self.state.refill() + } } ///| /// Create a new random number generator with [seed]. /// @alert unsafe "Panic if seed is not 32 bytes long" +#deprecated("Use `Rand::new(chacha8())` instead") pub fn new(seed~ : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") -> Rand { if seed.length() != 32 { abort("seed must be 32 bytes long") } - let src = @random_source.ChaCha8::new(seed) - { src, } + @random_source.ChaCha8::new(seed) as &Source +} + +///| +/// Create a new random number generator with [seed]. +/// @alert unsafe "Panic if seed is not 32 bytes long" +pub fn chacha8(seed~ : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") -> &Source { + if seed.length() != 32 { + abort("seed must be 32 bytes long") + } + @random_source.ChaCha8::new(seed) as &Source } -///| @alert deprecated "use `@random.new` instead" -pub fn Rand::new(seed~ : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") -> Rand { - new(seed~) +///| +/// Create a new random number generator with a given [Gen] source. +pub fn Rand::new(generator : &Source) -> Rand { + generator } ///| fn next(self : Rand) -> UInt64 { - for { - let x = self.src.state.next() - if x.1 { - return x.0 - } - self.src.state.refill() - } + self._.next() } ///| diff --git a/random/random.mbti b/random/random.mbti index ec11aeb36..1b5cba6c6 100644 --- a/random/random.mbti +++ b/random/random.mbti @@ -1,6 +1,8 @@ package "moonbitlang/core/random" // Values +fn chacha8(seed~ : Bytes = ..) -> &Source + fn double(Rand) -> Double fn float(Rand) -> Float @@ -9,6 +11,7 @@ fn int(Rand, limit~ : Int = ..) -> Int fn int64(Rand, limit~ : Int64 = ..) -> Int64 +#deprecated fn new(seed~ : Bytes = ..) -> Rand fn shuffle(Rand, Int, (Int, Int) -> Unit) -> Unit @@ -24,7 +27,7 @@ impl Rand { float(Self) -> Float int(Self, limit~ : Int = ..) -> Int int64(Self, limit~ : Int64 = ..) -> Int64 - new(seed~ : Bytes = ..) -> Self //deprecated + new(&Source) -> Self shuffle(Self, Int, (Int, Int) -> Unit) -> Unit uint(Self, limit~ : UInt = ..) -> UInt uint64(Self, limit~ : UInt64 = ..) -> UInt64 @@ -33,4 +36,7 @@ impl Rand { // Type aliases // Traits +pub(open) trait Source { + next(Self) -> UInt64 +}