use std::{
intrinsics::transmute,
io::{Read, Result},
mem::size_of,
ops::{Add, Mul, Rem, Sub},
ptr::addr_of,
};
use crate::{num_def::NumberSupport, zest_block::ZestBlock, zest_hash::zest4096};
#[derive(Clone, Copy)]
pub struct ZestRand {
seed: ZestBlock,
hash_output: [u8; 512],
byte_offset: usize,
}
impl ZestRand {
#[inline(always)]
pub fn new(seed: Option<ZestBlock>) -> ZestRand {
let mut initial = ZestRand {
seed: seed.unwrap_or_default(),
hash_output: [0; 512],
byte_offset: 0,
};
initial.hash_output = zest4096(initial.seed).data_u8();
initial
}
#[inline(always)]
pub fn seed(&mut self, seed: ZestBlock, byte_offset: usize) {
self.seed = seed;
self.hash_output = zest4096(self.seed).data_u8();
self.byte_offset = byte_offset & 0x1FF;
}
pub fn getseed(&self) -> (ZestBlock, usize) {
(self.seed, self.byte_offset)
}
#[inline(always)]
pub fn next_block(&mut self) {
self.seed.increment_block();
self.hash_output = zest4096(self.seed).data_u8();
}
#[inline(always)]
pub fn get_block_rehash(&mut self) -> ZestBlock {
zest4096(self.seed)
}
#[inline(always)]
pub fn get_block_data(&mut self) -> [u8; 512] {
self.hash_output
}
}
impl ZestRand {
#[inline(always)]
pub fn next_byte(&mut self) -> u8 {
let slice_ref = &self.hash_output;
let cast_slice: &[u8; 512] = unsafe { transmute(slice_ref) };
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 + Sized>(&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: NumberSupport + Copy>(&mut self) -> T {
unsafe { self.fill_rand() }
}
#[inline(always)]
pub fn bounded<
A: NumberSupport
+ Copy
+ Sub<Output = A>
+ Add<Output = A>
+ Mul<Output = A>
+ Rem<Output = A>
+ PartialOrd
+ From<u8>,
>(
&mut self,
min: A,
max: A,
) -> A {
let max_val: A = A::MAX;
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>();
}
not_biased.abs() % range + min
}
}
impl Default for ZestRand {
#[inline(always)]
fn default() -> Self {
Self::new(None)
}
}
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);
}
}
#[inline(always)]
pub unsafe fn fill_vec_any<T: Sized + Copy>(&mut self, len: usize) -> Vec<T> {
let mut data: Vec<T> = vec![];
data.resize_with(len, || self.fill_rand());
data
}
#[inline(always)]
pub fn fill_vec_num<T: NumberSupport + Copy>(&mut self, len: usize) -> Vec<T> {
unsafe { self.fill_vec_any(len) }
}
}