///|
/// WASM fallback RNG state.
///
/// MoonBit's wasm test runner does not provide a standard crypto import yet.
/// Keep the previous runtime-seeded ChaCha8 path for wasm and wasm-gc so
/// `moon test --target all` remains self-contained.
let global_rng : @random.Rand = @random.Rand::chacha8(seed=build_runtime_seed())
///|
fn mix_seed_state(state : UInt64) -> UInt64 {
let mut mixed = state
mixed = mixed ^ (mixed << 13)
mixed = mixed ^ (mixed >> 7)
mixed = mixed ^ (mixed << 17)
mixed
}
///|
fn absorb_seed_string(state : UInt64, value : String) -> UInt64 {
let mut mixed = state
for char in value {
mixed = mix_seed_state(mixed + char.to_int().to_uint64())
}
mixed
}
///|
fn build_runtime_seed() -> Bytes {
let mut state = @env.now()
for arg in @env.args() {
state = absorb_seed_string(state, arg)
}
match @env.current_dir() {
Some(cwd) => state = absorb_seed_string(state, cwd)
None => ()
}
if state == UInt64::default() {
state = Int::to_uint64(1)
}
let seed_bytes : Array[Byte] = Array::make(32, 0)
for i = 0; i < 32; i = i + 1 {
state = mix_seed_state(state + Int::to_uint64(i + 1))
seed_bytes[i] = state.to_byte()
}
Bytes::from_array(seed_bytes)
}
///|
fn get_random_bytes(size : Int) -> Result[Array[Int], NanoidError] {
let bytes = Array::make(size, 0)
for i = 0; i < size; i = i + 1 {
bytes[i] = global_rng.int(limit=256)
}
Ok(bytes)
}