use std::{
intrinsics::transmute,
io::{Read, Result},
mem::{size_of, zeroed},
num::Wrapping,
ptr::addr_of,
};
use num::{Bounded, Integer};
use crate::zest_hash::zest4096;
const MAGIC_BYTES: [u64; 2] = [
u64::from_be_bytes(*b"Bytes ar"),
u64::from_be_bytes(*b"e fun :)"),
];
#[derive(Clone, Copy)]
pub struct ZestRand {
seed: [u64; 62],
hash_output: Option<[u64; 64]>,
byte_offset: usize,
}
impl ZestRand {
#[inline(always)]
pub fn seed(&mut self, seed: [u64; 62], byte_offset: usize) {
if self.seed != seed {
self.seed = seed;
self.hash_output = None;
}
self.byte_offset = byte_offset & 0x1FF;
}
#[inline(always)]
fn next_block(&mut self) {
let mut carry: u64 = 1;
for elem in self.seed.iter_mut().rev() {
*elem = (Wrapping(*elem) + Wrapping(carry)).0;
carry = (*elem < carry) as u64;
}
self.hash_output = None;
}
#[inline(always)]
pub fn compute_block(&mut self) -> [u64; 64] {
zest4096(self.generate_input())
}
#[inline(always)]
fn generate_input(&self) -> [u64; 64] {
let mut block = [0_u64; 64];
let (seed_split, magic_split) = block.split_at_mut(62);
seed_split.copy_from_slice(&self.seed);
magic_split.copy_from_slice(&MAGIC_BYTES);
block
}
}
impl ZestRand {
#[inline(always)]
pub fn next_byte(&mut self) -> u8 {
if self.hash_output.is_none() {
self.hash_output = Some(self.compute_block());
}
let slice_ref = &self.hash_output.unwrap();
let cast_slice: &[u8; 512] = unsafe { transmute(slice_ref) };
dbg!(cast_slice);
let byte_val = cast_slice[self.byte_offset & 0x1FF];
self.byte_offset += 1;
if self.byte_offset >= 0x200 {
self.byte_offset = 0;
self.next_block();
}
byte_val
}
#[inline(always)]
pub fn next_bytes<const N: usize>(&mut self) -> [u8; N] {
let mut output = [0; N];
output.fill_with(|| self.next_byte());
output
}
#[inline(always)]
pub unsafe fn fill_rand<A: Copy>(&mut self) -> A {
let mut data = vec![];
data.resize_with(size_of::<A>(), || self.next_byte());
let data_address = addr_of!(data[..]) as *const A;
*data_address
}
#[inline(always)]
pub fn next_num<T: Integer + Copy>(&mut self) -> T {
unsafe { self.fill_rand() }
}
#[inline(always)]
pub fn bounded<A: Integer + Copy + From<u8> + Bounded>(&mut self, min: A, max: A) -> A {
let max_val: A = Bounded::max_value();
let mut not_biased = self.next_num::<A>();
let range = max - min;
while not_biased > (max_val - (((max_val % range) + A::from(1)) % range)) {
not_biased = self.next_num::<A>();
}
if not_biased < A::from(0) {
not_biased = not_biased * (A::from(0) - A::from(1));
}
not_biased % range + min
}
}
impl Default for ZestRand {
#[inline(always)]
fn default() -> Self {
unsafe { zeroed() }
}
}
impl Iterator for ZestRand {
type Item = u8;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
Some(self.next_byte())
}
}
impl Read for ZestRand {
#[inline(always)]
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
buf.fill_with(|| self.next_byte());
Ok(buf.len())
}
#[inline(always)]
fn read_to_end(&mut self, _: &mut Vec<u8>) -> Result<usize> {
panic!();
}
}
impl ZestRand {
#[inline(always)]
pub fn slice_shuffle<T: Sized + Copy>(&mut self, slice: &mut [T]) {
for i in 0..slice.len() {
let swap_index = self.bounded(i, slice.len());
slice.swap(i, swap_index);
}
}
}