diff --git a/Cargo.toml b/Cargo.toml index 1c311e9..4f02b41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,8 @@ keywords = ["rng", "random", "xorshift", "xoroshiro", "splitmix"] [dependencies] lazy_static = "0.2" -rand = "0.3" +rand = "0.6" +rand_core = "0.3" [dev-dependencies] time = "0.1" diff --git a/src/lib.rs b/src/lib.rs index 5d1dc7f..65a0bfc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ //! Implementation of the high performance xoroshiro128+, xorshift128+, xorshift1024*, and splitmix64 pseudo random number generators. //! -//! Implements the `Rand`, `Rng`, and `SeedableRng` traits from the [rand crate](https://crates.io/crates/rand). +//! Implements the `RngCore` and `SeedableRng` traits from the [rand_core crate](https://crates.io/crates/rand_core). //! //! # Usage //! ```toml @@ -122,6 +122,7 @@ extern crate lazy_static; extern crate rand; +extern crate rand_core; pub mod splitmix64; pub mod xoroshiro128; @@ -133,7 +134,7 @@ pub use xoroshiro128::Xoroshiro128; pub use xorshift128::Xorshift128; pub use xorshift1024::Xorshift1024; -pub use rand::{Rand, Rng, SeedableRng, StdRng}; +pub use rand::{Rng, SeedableRng, StdRng}; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -147,24 +148,24 @@ pub trait RngJump { } -/// Create a jumpable random number generator. Each call increments -/// the generator jump state. -pub fn thread_rng <'a, T: Rand+Rng+RngJump+SeedableRng<&'a [u64]>>() -> T { - lazy_static! { - static ref THREAD_RNG_STATE : Vec = { - match StdRng::new() { - Ok(mut r) => r.gen_iter::().take(16).collect::>(), - Err(e) => panic!("could not initialize seeding rng: {}", e) - } - }; - static ref THREAD_RNG_INSTANCE : AtomicUsize = AtomicUsize::new(0); - }; +// /// Create a jumpable random number generator. Each call increments +// /// the generator jump state. +// pub fn thread_rng <'a, T: RngCore+RngJump+SeedableRng>() -> T { +// lazy_static! { +// static ref THREAD_RNG_STATE : Vec = { +// match StdRng::new() { +// Ok(mut r) => r.gen_iter::().take(16).collect::>(), +// Err(e) => panic!("could not initialize seeding rng: {}", e) +// } +// }; +// static ref THREAD_RNG_INSTANCE : AtomicUsize = AtomicUsize::new(0); +// }; - let mut rng:T = SeedableRng::from_seed(&(*THREAD_RNG_STATE)[..]); - rng.jump((*THREAD_RNG_INSTANCE).fetch_add(1, Ordering::SeqCst)); +// let mut rng:T = SeedableRng::from_seed(&(*THREAD_RNG_STATE)[..]); +// rng.jump((*THREAD_RNG_INSTANCE).fetch_add(1, Ordering::SeqCst)); - rng -} +// rng +// } // Taken from the lib.rs in the rand crate. diff --git a/src/splitmix64.rs b/src/splitmix64.rs index 65a557d..1fc42f9 100644 --- a/src/splitmix64.rs +++ b/src/splitmix64.rs @@ -8,8 +8,10 @@ //! The `SplitMix64` random number generator. +use std::mem; use std::num::Wrapping as w; -use rand::{Rand, Rng, SeedableRng}; +use rand::Rng; +use rand_core::{Error, SeedableRng, RngCore, impls}; /// A random number generator that uses the splitmix64 algorithm [1]. /// @@ -37,7 +39,7 @@ use rand::{Rand, Rng, SeedableRng}; #[derive(Copy, Clone)] pub struct SplitMix64(u64); -impl Rng for SplitMix64 { +impl RngCore for SplitMix64 { #[inline] fn next_u32(&mut self) -> u32 { self.next_u64() as u32 @@ -51,24 +53,35 @@ impl Rng for SplitMix64 { z = (z ^ (z >> 27)) * w(0x94D049BB133111EB_u64); (z ^ (z >> 31)).0 } -} -impl SeedableRng for SplitMix64 { - fn reseed(&mut self, seed: u64) { - self.0 = seed; + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest) } - fn from_seed(seed: u64) -> SplitMix64 { - SplitMix64(seed) + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) } } -impl Rand for SplitMix64 { - fn rand(other: &mut R) -> SplitMix64 { - SeedableRng::from_seed(other.gen()) +impl SplitMix64 { + pub fn new(seed: u64) -> Self { + SplitMix64(seed) } } +impl SeedableRng for SplitMix64 { + type Seed = [u8; 8]; + + fn from_seed(seed: Self::Seed) -> Self { + let u64_seed = unsafe { mem::transmute(seed) }; + SplitMix64::new(u64_seed) + } + + fn from_rng(mut rng: R) -> Result { + Ok(SplitMix64(rng.gen())) + } +} #[cfg(test)] mod tests { @@ -130,7 +143,7 @@ mod tests { 14635952304031724449, 15419692541594102413]; - let mut rng: SplitMix64 = SeedableRng::from_seed(seed); + let mut rng = SplitMix64::new(seed); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(::test::iter_eq(t_vals, vals)); } diff --git a/src/xoroshiro128.rs b/src/xoroshiro128.rs index f5b5232..89461df 100644 --- a/src/xoroshiro128.rs +++ b/src/xoroshiro128.rs @@ -8,14 +8,14 @@ //! The Xoroshiro128+ random number generator. +use std::mem; use std::num::Wrapping as w; -use rand::{Rand, Rng, SeedableRng}; +use rand::Rng; +use rand_core::{Error, SeedableRng, RngCore, impls}; use RngJump; -const STATE_SIZE: usize = 2; - /// A random number generator that uses the xoroshiro128+ algorithm [1]. /// /// # Description @@ -50,7 +50,6 @@ const STATE_SIZE: usize = 2; #[derive(Copy, Clone)] pub struct Xoroshiro128([u64; 2]); -static EMPTY: Xoroshiro128 = Xoroshiro128([0, 0]); static JUMP: [u64; 2] = [0xbeac0467eba5facb, 0xd86b048b86aa9922]; #[inline] @@ -58,7 +57,7 @@ fn rotl(x: u64, k: i32) -> u64 { (x << k) | (x >> (64 - k)) } -impl Rng for Xoroshiro128 { +impl RngCore for Xoroshiro128 { fn next_u32(&mut self) -> u32 { self.next_u64() as u32 } @@ -75,34 +74,38 @@ impl Rng for Xoroshiro128 { result.0 } -} -impl<'a> SeedableRng<&'a [u64]> for Xoroshiro128 { - fn reseed(&mut self, seed: &'a [u64]) { - if seed.len() < 2 { - panic!("Xoroshiro128 seed needs at least two u64s for seeding."); - } - self.0[0] = seed[0]; - self.0[1] = seed[1]; + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest) } - fn from_seed(seed: &'a [u64]) -> Xoroshiro128 { - let mut rng = EMPTY; - rng.reseed(seed); - rng + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) } + } -impl Rand for Xoroshiro128 { - fn rand(other: &mut R) -> Xoroshiro128 { - let mut key: [u64; STATE_SIZE] = [0; STATE_SIZE]; - for word in &mut key { - *word = other.gen(); - } - SeedableRng::from_seed(&key[..]) +impl Xoroshiro128 { + pub fn new(seed: [u64; 2]) -> Self { + Xoroshiro128(seed) } } +impl SeedableRng for Xoroshiro128 { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + let u64_seed = unsafe { mem::transmute(seed) }; + Xoroshiro128(u64_seed) + } + + fn from_rng(mut rng: R) -> Result { + Ok(Xoroshiro128([rng.gen(), rng.gen()])) + } + +} + impl RngJump for Xoroshiro128 { fn jump(&mut self, count: usize) { for _ in 0..count { @@ -186,7 +189,7 @@ mod tests { 6715575954761285513]; let states = [seed, seed]; - let mut rng: Xoroshiro128 = SeedableRng::from_seed(&states[..]); + let mut rng = Xoroshiro128::new(states); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(::test::iter_eq(t_vals, vals)); } diff --git a/src/xorshift1024.rs b/src/xorshift1024.rs index c3eae4f..22c55ad 100644 --- a/src/xorshift1024.rs +++ b/src/xorshift1024.rs @@ -10,14 +10,14 @@ #![cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))] +use std::mem; use std::num::Wrapping as w; -use rand::{Rand, Rng, SeedableRng}; +use rand::Rng; +use rand_core::{Error, SeedableRng, RngCore, impls}; use RngJump; -const STATE_SIZE: usize = 16; - /// A random number generator that uses the xorshift1024* algorithm [1]. /// /// # Description @@ -47,10 +47,10 @@ pub struct Xorshift1024 { p: usize, } -static EMPTY: Xorshift1024 = Xorshift1024 { - state: [0; 16], - p: 0, -}; +// A newtype is used so that the required Default and AsMut<[u8]> traits +// can be implemented for SeedableRng::Seed. +pub struct U8Seed(pub [u8; 128]); + static JUMP: [u64; 16] = [0x84242f96eca9c41d, 0xa3c65b8776f96855, 0x5b34a39f070b5837, @@ -70,7 +70,7 @@ static JUMP: [u64; 16] = [0x84242f96eca9c41d, -impl Rng for Xorshift1024 { +impl RngCore for Xorshift1024 { #[inline] fn next_u32(&mut self) -> u32 { self.next_u64() as u32 @@ -87,34 +87,52 @@ impl Rng for Xorshift1024 { (w(self.state[self.p]) * w(1181783497276652981_u64)).0 } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } } -impl<'a> SeedableRng<&'a [u64]> for Xorshift1024 { - fn reseed(&mut self, seed: &'a [u64]) { - if seed.len() < 16 { - panic!("Xorshift1024 seed needs at least 16 u64s for seeding."); - } +impl Xorshift1024 { + pub fn new(seed: [u64; 16]) -> Self { + Xorshift1024 { state: seed, p: 0 } + } +} - for (index, element) in seed.iter().enumerate() { - self.state[index] = *element; - } +impl Default for U8Seed { + fn default() -> Self { + U8Seed([0; 128]) } +} - fn from_seed(seed: &'a [u64]) -> Xorshift1024 { - let mut rng = EMPTY; - rng.reseed(seed); - rng +impl AsMut<[u8]> for U8Seed { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 } } -impl Rand for Xorshift1024 { - fn rand(other: &mut R) -> Xorshift1024 { - let mut key: [u64; STATE_SIZE] = [0; STATE_SIZE]; - for word in &mut key { - *word = other.gen(); - } - SeedableRng::from_seed(&key[..]) +impl SeedableRng for Xorshift1024 { + type Seed = U8Seed; + + fn from_seed(seed: Self::Seed) -> Self { + let u64_seed = unsafe { mem::transmute(seed) }; + Xorshift1024::new(u64_seed) + } + + fn from_rng(mut rng: R) -> Result { + let seed = [rng.gen(), rng.gen(), rng.gen(), rng.gen(), + rng.gen(), rng.gen(), rng.gen(), rng.gen(), + rng.gen(), rng.gen(), rng.gen(), rng.gen(), + rng.gen(), rng.gen(), rng.gen(), rng.gen()]; + + Ok(Xorshift1024 { state: seed, p: 0 }) } + } impl RngJump for Xorshift1024 { @@ -200,7 +218,7 @@ mod tests { 14943324017293890156]; let states = [seed; 16]; - let mut rng: Xorshift1024 = SeedableRng::from_seed(&states[..]); + let mut rng = Xorshift1024::new(states); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(::test::iter_eq(t_vals, vals)); } diff --git a/src/xorshift128.rs b/src/xorshift128.rs index 87a7c6b..7dab374 100644 --- a/src/xorshift128.rs +++ b/src/xorshift128.rs @@ -8,14 +8,14 @@ //! The Xorshift128+ random number generator. +use std::mem; use std::num::Wrapping as w; -use rand::{Rand, Rng, SeedableRng}; +use rand::Rng; +use rand_core::{Error, SeedableRng, RngCore, impls}; use RngJump; -const STATE_SIZE: usize = 2; - /// A random number generator that uses the xorshift128+ algorithm [1]. /// /// # Description @@ -47,10 +47,9 @@ const STATE_SIZE: usize = 2; #[derive(Copy, Clone)] pub struct Xorshift128([u64; 2]); -static EMPTY: Xorshift128 = Xorshift128([0, 0]); static JUMP: [u64; 2] = [0x8a5cd789635d2dff, 0x121fd2155c472f96]; -impl Rng for Xorshift128 { +impl RngCore for Xorshift128 { fn next_u32(&mut self) -> u32 { self.next_u64() as u32 } @@ -65,33 +64,34 @@ impl Rng for Xorshift128 { self.0[1] = (s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5)).0; result.0 } -} -impl<'a> SeedableRng<&'a [u64]> for Xorshift128 { - fn reseed(&mut self, seed: &'a [u64]) { - if seed.len() < 2 { - panic!("Xorshift128 seed needs at least two u64s for seeding."); - } - self.0[0] = seed[0]; - self.0[1] = seed[1]; + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest) } - // Create a Xorshift128 generator from a seeded state u64 array. - // Seed must have at least 2 elements. - fn from_seed(seed: &'a [u64]) -> Xorshift128 { - let mut rng = EMPTY; - rng.reseed(seed); - rng + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) } + } -impl Rand for Xorshift128 { - fn rand(other: &mut R) -> Xorshift128 { - let mut key: [u64; STATE_SIZE] = [0; STATE_SIZE]; - for word in &mut key { - *word = other.gen(); - } - SeedableRng::from_seed(&key[..]) +impl Xorshift128 { + pub fn new(seed: [u64; 2]) -> Self { + Xorshift128(seed) + } +} + +impl SeedableRng for Xorshift128 { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + let u64_seed = unsafe { mem::transmute(seed) }; + Xorshift128::new(u64_seed) + } + + fn from_rng(mut rng: R) -> Result { + Ok(Xorshift128([rng.gen(), rng.gen()])) } } @@ -181,7 +181,7 @@ mod tests { 4972002347465534564]; let states = [seed, seed]; - let mut rng: Xorshift128 = SeedableRng::from_seed(&states[..]); + let mut rng = Xorshift128::new(states); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(::test::iter_eq(t_vals, vals)); } diff --git a/tests/rng_seeding.rs b/tests/rng_seeding.rs index 78317f7..1432e52 100644 --- a/tests/rng_seeding.rs +++ b/tests/rng_seeding.rs @@ -81,8 +81,8 @@ fn test_xorshift128_sm64_seed() { 367719864125592010, 10625882457741862049]; - let mut sm: SplitMix64 = SeedableRng::from_seed(seed); - let mut rng: Xorshift128 = Rand::rand(&mut sm); + let mut sm = SplitMix64::new(seed); + let mut rng = Xorshift128::from_rng(&mut sm).unwrap(); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(iter_eq(t_vals, vals)); } @@ -142,8 +142,8 @@ fn test_xoroshiro128_sm64_seed() { 1951146658863428296, 9961210433054140615]; - let mut sm: SplitMix64 = SeedableRng::from_seed(seed); - let mut rng: Xoroshiro128 = Rand::rand(&mut sm); + let mut sm = SplitMix64::new(seed); + let mut rng = Xoroshiro128::from_rng(sm).unwrap(); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(iter_eq(t_vals, vals)); } @@ -202,8 +202,8 @@ fn test_xorshift1024_sm64_seed() { 8582117804084448577, 7011339168466747000]; - let mut sm: SplitMix64 = SeedableRng::from_seed(seed); - let mut rng: Xorshift1024 = Rand::rand(&mut sm); + let mut sm = SplitMix64::new(seed); + let mut rng = Xorshift1024::from_rng(sm).unwrap(); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(iter_eq(t_vals, vals)); } @@ -263,8 +263,8 @@ fn test_xoroshiro128_sm64_seed_jumps() { 8821738610530612520, 5335768027764772758]; - let mut sm: SplitMix64 = SeedableRng::from_seed(seed); - let mut rng: Xoroshiro128 = Rand::rand(&mut sm); + let mut sm = SplitMix64::new(seed); + let mut rng = Xoroshiro128::from_rng(&mut sm).unwrap(); rng.jump(10); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(iter_eq(t_vals, vals)); @@ -325,8 +325,8 @@ fn test_xorshift128_sm64_seed_jumps() { 12688408626692700841, 1374630186161923550]; - let mut sm: SplitMix64 = SeedableRng::from_seed(seed); - let mut rng: Xorshift128 = Rand::rand(&mut sm); + let mut sm = SplitMix64::new(seed); + let mut rng = Xorshift128::from_rng(sm).unwrap(); rng.jump(10); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(iter_eq(t_vals, vals)); @@ -387,8 +387,8 @@ fn test_xorshift1024_sm64_seed_jumps() { 7073407240019580288, 544911792544382917]; - let mut sm: SplitMix64 = SeedableRng::from_seed(seed); - let mut rng: Xorshift1024 = Rand::rand(&mut sm); + let mut sm = SplitMix64::new(seed); + let mut rng = Xorshift1024::from_rng(sm).unwrap(); rng.jump(10); let vals = rng.gen_iter::().take(t_vals.len()).collect::>(); assert!(iter_eq(t_vals, vals));