use rand::SeedableRng; use rand_xoshiro::Xoshiro256StarStar; /// Convert an RNG state buffer to an instance of [`Xoshiro256StarStar`]. /// /// While [`SeedableRng::from_seed`] is an infallible function, /// it relies on some methods that can't be compiled by the SPIR-V /// backend (specifically, formatting functions in the core crate). /// /// In practice, the xoshiro RNG state is entirely defined by its seed, /// so this function does the work of [`SeedableRng::from_seed`] by /// transmuting the seed value to an RNG instance. /// /// This function assumes a properly-initialized state array; /// output may silently degenerate if the initial state is all zeros, /// so this module is private to the crate. pub(crate) fn xoshiro256starstar_from_seed( rng_state: ::Seed, ) -> Xoshiro256StarStar { let mut rng_state_actual = [0u64; 4]; // NOTE: Bit shifting is tedious, but we don't have great alternatives: // - `chunks_exact` has issues with pointer casting // - `u64::from_le_bytes` has issues with `OpBitcast` in SPIR-V validation for i in 0..rng_state_actual.len() { for j in 0..size_of::() { rng_state_actual[i] |= (rng_state[i * size_of::() + j] as u64) << j * 8; } } unsafe { core::mem::transmute(rng_state_actual) } } #[cfg(test)] mod test { use crate::rng::xoshiro256starstar_from_seed; use core::iter::zip; use rand::{RngExt, SeedableRng}; use rand_xoshiro::Xoshiro256StarStar; #[test] fn match_seeded() { let mut seed: ::Seed = [0u8; 32]; for i in 0..seed.len() { seed[i] = i as u8; } let rng1 = Xoshiro256StarStar::from_seed(seed).random_iter::(); let rng2 = xoshiro256starstar_from_seed(seed).random_iter::(); zip(rng1, rng2) .take(100) .for_each(|(rng1_value, rng2_value)| assert_eq!(rng1_value, rng2_value)); } }