pub struct WordSource<'a> {
pub(crate) name: String,
pub(crate) word_bits: u32,
pub(crate) sampler: Box<dyn FnMut() -> u64 + 'a>,
}
impl<'a> WordSource<'a> {
pub fn new(name: impl Into<String>, word_bits: u32, sampler: impl FnMut() -> u64 + 'a) -> Self {
Self {
name: name.into(),
word_bits,
sampler: Box::new(sampler),
}
}
}
#[cfg(feature = "urng")]
pub trait UrngSeed32: urng::Rng32 + Sized {
fn from_seed(seed: u32) -> Self;
}
#[cfg(feature = "urng")]
pub trait UrngSeed64: urng::Rng64 + Sized {
fn from_seed(seed: u64) -> Self;
}
#[cfg(feature = "urng")]
macro_rules! impl_urng_seed32 {
($($t:ty),* $(,)?) => {
$(
impl UrngSeed32 for $t {
fn from_seed(seed: u32) -> Self {
Self::new(seed)
}
}
)*
};
}
#[cfg(feature = "urng")]
macro_rules! impl_urng_seed64 {
($($t:ty),* $(,)?) => {
$(
impl UrngSeed64 for $t {
fn from_seed(seed: u64) -> Self {
Self::new(seed)
}
}
)*
};
}
#[cfg(feature = "urng")]
impl_urng_seed32!(urng::Jsf32, urng::Sfc32, urng::SplitMix32, urng::Xorshift32);
#[cfg(feature = "urng")]
impl UrngSeed32 for urng::Pcg32 {
fn from_seed(seed: u32) -> Self {
Self::new(seed as u64)
}
}
#[cfg(feature = "urng")]
impl_urng_seed64!(urng::Sfc64, urng::SplitMix64, urng::Xorshift64);
#[cfg(feature = "rand")]
pub trait RandSource {
fn sample_f64(&mut self) -> f64;
fn sample_word(&mut self) -> u64;
}
#[cfg(feature = "rand")]
impl<R: rand_core::Rng> RandSource for R {
fn sample_f64(&mut self) -> f64 {
crate::unit_f64_from_u64(self.next_u64())
}
fn sample_word(&mut self) -> u64 {
self.next_u64()
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "urng")]
#[test]
fn from_urng32_and_from_urng64_are_seeded_from_the_suite() {
use crate::{ChiSqSuite, NistSuite};
use urng::{Sfc32, Sfc64};
let chisq = ChiSqSuite::new(1)
.from_urng32::<Sfc32>()
.unwrap()
.from_urng64::<Sfc64>()
.unwrap()
.run()
.unwrap();
assert!(chisq.contains_key("Sfc32"));
assert!(chisq.contains_key("Sfc64"));
let nist = NistSuite::new(1)
.from_urng32::<Sfc32>()
.unwrap()
.run()
.unwrap();
assert!(nist.contains_key("Sfc32"));
}
#[cfg(feature = "rand")]
#[test]
fn from_rand_is_seeded_from_the_suite() {
use crate::ChiSqSuite;
let results = ChiSqSuite::new(1)
.from_rand::<rand::rngs::StdRng>()
.unwrap()
.run()
.unwrap();
assert!(results.contains_key("StdRng"));
}
#[test]
fn from_custom_accepts_custom_type() {
use crate::{ChiSqSuite, NistSuite, WordSource};
struct MyRng(u64);
impl<'a> From<MyRng> for WordSource<'a> {
fn from(mut rng: MyRng) -> Self {
WordSource::new("MyRng", 64, move || {
rng.0 = rng.0.wrapping_mul(6364136223846793005).wrapping_add(1);
rng.0
})
}
}
let results = ChiSqSuite::new(1)
.from_custom(MyRng(1))
.unwrap()
.run()
.unwrap();
assert!(results.contains_key("MyRng"));
let nist = NistSuite::new(1)
.from_custom(MyRng(2))
.unwrap()
.run()
.unwrap();
assert!(nist.contains_key("MyRng"));
}
}