#![allow(dead_code)]
use core::hash::{Hash, Hasher};
#[cfg(feature = "std")]
use std::collections::hash_map::DefaultHasher;
#[cfg(feature = "std")]
use std::time::{SystemTime, UNIX_EPOCH};
#[deprecated(
since = "1.0.0",
note = "Not cryptographically secure. Use rand + getrandom for production."
)]
pub struct SimplePrng {
state: u64,
}
#[allow(deprecated)]
impl SimplePrng {
#[cfg(feature = "std")]
pub fn new() -> Self {
let seed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(0);
Self::with_seed(seed)
}
pub fn with_seed(seed: u64) -> Self {
SimplePrng {
state: hash_value(&seed),
}
}
pub fn next_u64(&mut self) -> u64 {
let mut x = self.state;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
self.state = x;
x
}
pub fn range(&mut self, min: u64, max: u64) -> Option<u64> {
if min >= max {
return None;
}
let range = max - min;
Some((self.next_u64() % range) + min)
}
pub fn next_bool(&mut self) -> bool {
self.next_u64() % 2 == 0
}
}
#[cfg(feature = "std")]
#[allow(deprecated)]
impl Default for SimplePrng {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "std")]
fn hash_value<T: Hash>(value: &T) -> u64 {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
hasher.finish()
}
#[cfg(not(feature = "std"))]
fn hash_value<T>(value: &T) -> u64 {
0xdeadbeef
}
#[cfg(test)]
#[cfg(feature = "std")]
mod tests {
use super::*;
#[test]
#[allow(deprecated)]
fn test_prng_deterministic_with_seed() {
let mut prng1 = SimplePrng::with_seed(12345);
let mut prng2 = SimplePrng::with_seed(12345);
for _ in 0..100 {
assert_eq!(prng1.next_u64(), prng2.next_u64());
}
}
#[test]
#[allow(deprecated)]
fn test_prng_different_seeds() {
let mut prng1 = SimplePrng::with_seed(12345);
let mut prng2 = SimplePrng::with_seed(54321);
assert_ne!(prng1.next_u64(), prng2.next_u64());
}
#[test]
#[allow(deprecated)]
fn test_prng_range() {
let mut prng = SimplePrng::with_seed(12345);
for _ in 0..1000 {
let value = prng.range(10, 20).unwrap();
assert!(value >= 10 && value < 20);
}
}
#[test]
#[allow(deprecated)]
fn test_prng_range_invalid() {
let mut prng = SimplePrng::with_seed(12345);
assert!(prng.range(20, 10).is_none());
assert!(prng.range(10, 10).is_none());
}
#[test]
#[allow(deprecated)]
fn test_prng_bool() {
let mut prng = SimplePrng::with_seed(12345);
let mut trues = 0;
let mut falses = 0;
for _ in 0..1000 {
if prng.next_bool() {
trues += 1;
} else {
falses += 1;
}
}
assert!(trues > 300 && trues < 700);
assert!(falses > 300 && falses < 700);
}
}