use rand::thread_rng;
use rand::RngCore;
use super::ExclusiveId;
use super::Id;
#[cfg(feature = "deterministic")]
pub mod deterministic {
use rand::rngs::StdRng;
use rand::SeedableRng;
use std::cell::RefCell;
thread_local! {
pub(super) static SOURCE: RefCell<Option<StdRng>> = const { RefCell::new(None) };
}
pub fn seed_ids(seed: u64) {
SOURCE.with(|s| *s.borrow_mut() = Some(StdRng::seed_from_u64(seed)));
}
pub fn unseed_ids() {
SOURCE.with(|s| *s.borrow_mut() = None);
}
pub fn try_fill(buf: &mut [u8]) -> bool {
use rand::RngCore;
SOURCE.with(|s| {
s.borrow_mut().as_mut().map(|rng| rng.fill_bytes(buf)).is_some()
})
}
}
#[cfg(feature = "deterministic")]
pub use deterministic::{seed_ids, unseed_ids};
pub fn rngid() -> ExclusiveId {
#[cfg(feature = "deterministic")]
{
let seeded = deterministic::SOURCE.with(|s| {
s.borrow_mut().as_mut().map(|rng| {
let mut id = [0; 16];
rng.fill_bytes(&mut id[..]);
id
})
});
if let Some(id) = seeded {
return ExclusiveId::force(
Id::new(id).expect("the probability for a zero id from the seeded stream is negligible"),
);
}
}
let mut rng = thread_rng();
let mut id = [0; 16];
rng.fill_bytes(&mut id[..]);
ExclusiveId::force(Id::new(id).expect("The probability for rng = 0 should be neglegible."))
}
#[cfg(all(test, feature = "deterministic"))]
mod tests {
use super::*;
#[test]
fn seeded_ids_reproduce() {
seed_ids(42);
let a1 = *rngid();
let a2 = *rngid();
seed_ids(42);
let b1 = *rngid();
let b2 = *rngid();
unseed_ids();
assert_eq!(a1, b1);
assert_eq!(a2, b2);
assert_ne!(a1, a2);
}
#[test]
fn unseeded_ids_differ_across_reseeds_of_different_seeds() {
seed_ids(1);
let a = *rngid();
seed_ids(2);
let b = *rngid();
unseed_ids();
assert_ne!(a, b);
}
}