use crate::consts::{INCREMENTOR, INIT_INC, INIT_STATE};
#[cfg(feature = "std")]
use std::{
hash::{Hash, Hasher},
num::Wrapping,
};
#[cfg(not(feature = "std"))]
use core::{
hash::{Hash, Hasher},
num::Wrapping,
};
use rand_core::{impls, Error, RngCore, SeedableRng};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
mod consts;
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Pcg {
state: u64,
inc: u64,
}
impl Pcg {
pub fn new(seed: u64, seq: u64) -> Pcg {
Pcg {
state: seed,
inc: (seq << 1) | 1,
}
}
}
impl Default for Pcg {
fn default() -> Self {
Pcg {
state: INIT_STATE,
inc: INIT_INC,
}
}
}
impl RngCore for Pcg {
fn next_u32(&mut self) -> u32 {
self.next_u64() as u32
}
fn next_u64(&mut self) -> u64 {
let old_state = self.state;
self.state = (Wrapping(old_state) * Wrapping(INCREMENTOR) + Wrapping(self.inc)).0;
let xor_shifted = (old_state >> 18) ^ old_state >> 27;
let rot = (old_state >> 59) as i64;
(xor_shifted >> rot as u64) | (xor_shifted << ((-rot) & 31))
}
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> {
self.fill_bytes(dest);
Ok(())
}
}
const N: usize = 8;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PcgSeed(pub [u8; N]);
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct U64(pub u64);
const MASK: u8 = 0b11111111;
impl From<PcgSeed> for U64 {
fn from(seed: PcgSeed) -> Self {
let mut res: u64 = 0;
for (i, &byte) in seed.0.iter().enumerate() {
let shift_up = (N - i - 1) * 8;
let byte = byte as u64;
let block = (byte << shift_up) as u64;
res |= block;
}
U64(res)
}
}
impl Default for PcgSeed {
fn default() -> Self {
Self([0; N])
}
}
impl AsMut<[u8]> for PcgSeed {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl Hash for PcgSeed {
fn hash<H: Hasher>(&self, state: &mut H) {
let seed_vec = self.0.to_vec();
seed_vec.hash(state);
}
}
impl From<u64> for PcgSeed {
fn from(init: u64) -> Self {
let mut seed: [u8; N] = [0; N];
for i in 0..N {
let shift_factor = (N - i - 1) * 8;
let section = (init >> shift_factor) as u8;
seed[i] = section & MASK;
}
PcgSeed(seed)
}
}
impl From<U64> for PcgSeed {
fn from(init: U64) -> Self {
init.0.into()
}
}
impl SeedableRng for Pcg {
type Seed = PcgSeed;
fn from_seed(seed: Self::Seed) -> Pcg {
Pcg::new(U64::from(seed).0, INIT_INC)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fmt::{Binary, Debug};
fn assert_eq_binary<T>(a: T, b: T)
where
T: PartialEq + Debug + Binary,
{
let b_str_a = format!("{:b}", a);
let b_str_b = format!("{:b}", b);
assert_eq!(b_str_a, b_str_b);
}
#[test]
fn test_seed_to_u64() {
let mut seed = PcgSeed::default();
seed.0[0] = MASK;
let converted_int = U64::from(seed);
let expected = (MASK as u64) << ((N - 1) * 8);
assert_eq_binary(converted_int.0, expected);
let mut seed = PcgSeed::default();
seed.0[N - 1] = MASK;
let converted_int = U64::from(seed);
let expected = MASK as u64;
assert_eq_binary(converted_int.0, expected)
}
#[test]
fn test_u64_to_seed() {
let integer = (MASK as u64) << ((N - 1) * 8);
let seed = PcgSeed::from(integer);
let mut expected = PcgSeed::default();
expected.0[0] = MASK;
assert_eq!(seed, expected);
let integer = MASK as u64;
let seed = PcgSeed::from(integer);
let mut expected = PcgSeed::default();
expected.0[N - 1] = MASK;
assert_eq!(seed, expected);
}
}