#![no_std]
use core::cmp::{max, min};
use awint::awi::*;
use rand_core::{RngCore, SeedableRng};
use rand_xoshiro::Xoshiro128StarStar;
#[derive(Debug)]
pub struct StarRng {
rng: Xoshiro128StarStar,
buf: inlawi_ty!(64),
used: u8,
}
macro_rules! next {
($($name:ident $x:ident $from:ident $to:ident),*,) => {
$(
pub fn $name(&mut self) -> $x {
let mut res = InlAwi::$from(0);
let mut processed = 0;
loop {
let remaining_in_buf = usize::from(Self::BW_U8.wrapping_sub(self.used));
let remaining = res.bw().wrapping_sub(processed);
if remaining == 0 {
break
}
if remaining < remaining_in_buf {
res.field(
processed,
&self.buf,
usize::from(self.used),
remaining
).unwrap();
self.used = self.used.wrapping_add(remaining as u8);
break
} else {
res.field(
processed,
&self.buf,
usize::from(self.used),
remaining_in_buf
).unwrap();
processed = processed.wrapping_add(remaining_in_buf);
self.buf = InlAwi::from_u64(self.rng.next_u64());
self.used = 0;
}
}
res.$to()
}
)*
};
}
macro_rules! out_of {
($($fn:ident, $max:expr, $bw:expr);*;) => {
$(
pub fn $fn(&mut self, num: u8) -> bool {
if num == 0 {
false
} else if num >= $max {
true
} else {
let mut tmp: inlawi_ty!($bw) = InlAwi::zero();
tmp.u8_(num);
self.next_bits(&mut tmp);
num > tmp.to_u8()
}
}
)*
};
}
macro_rules! uniform {
($($fn:ident, $x:ident, $to_x:ident, $bw:expr);*;) => {
$(
#[must_use]
pub fn $fn(&mut self, max: $x) -> $x {
if max == 0 {
0
} else {
let w = if max >= (1 << ($bw - 1)) {
$bw
} else {
max.wrapping_add(1).next_power_of_two().trailing_zeros() as usize
};
let mut tmp: inlawi_ty!($bw) = InlAwi::zero();
for _ in 0..64 {
self.next_bits_width(&mut tmp, w).unwrap();
let test_val = tmp.$to_x();
if test_val <= max {
return test_val;
}
}
return 0;
}
}
)*
}
}
impl StarRng {
const BW_U8: u8 = 64;
next!(
next_u8 u8 from_u8 to_u8,
next_u16 u16 from_u16 to_u16,
next_u32 u32 from_u32 to_u32,
next_u64 u64 from_u64 to_u64,
next_u128 u128 from_u128 to_u128,
);
out_of!(
out_of_4, 4, 2;
out_of_8, 8, 3;
out_of_16, 16, 4;
out_of_32, 32, 5;
out_of_64, 64, 6;
out_of_128, 128, 7;
);
uniform!(
uniform_u8, u8, to_u8, 8;
uniform_u16, u16, to_u16, 16;
uniform_u32, u32, to_u32, 32;
uniform_u64, u64, to_u64, 64;
uniform_u128, u128, to_u128, 128;
);
pub fn new(seed: u64) -> Self {
let mut rng = Xoshiro128StarStar::seed_from_u64(seed);
let buf = InlAwi::from_u64(rng.next_u64());
Self { rng, buf, used: 0 }
}
pub fn next_bool(&mut self) -> bool {
let res = self.buf.get(usize::from(self.used)).unwrap();
self.used += 1;
if self.used >= Self::BW_U8 {
self.buf = InlAwi::from_u64(self.rng.next_u64());
self.used = 0;
}
res
}
pub fn out_of_256(&mut self, num: u8) -> bool {
if num == 0 {
false
} else {
let mut tmp = InlAwi::from_u8(num);
tmp.u8_(num);
self.next_bits(&mut tmp);
num > tmp.to_u8()
}
}
#[must_use]
pub fn next_bits_width(&mut self, bits: &mut Bits, width: usize) -> Option<()> {
if width > bits.bw() {
return None
}
bits.zero_();
if width == 0 {
return Some(())
}
let mut processed = 0;
loop {
let remaining_in_buf = usize::from(Self::BW_U8.wrapping_sub(self.used));
let remaining = width.wrapping_sub(processed);
if remaining == 0 {
break
}
if remaining < remaining_in_buf {
bits.field(processed, &self.buf, usize::from(self.used), remaining)
.unwrap();
self.used = self.used.wrapping_add(remaining as u8);
break
} else {
bits.field(
processed,
&self.buf,
usize::from(self.used),
remaining_in_buf,
)
.unwrap();
processed = processed.wrapping_add(remaining_in_buf);
self.buf = InlAwi::from_u64(self.rng.next_u64());
self.used = 0;
}
}
Some(())
}
pub fn next_bits(&mut self, bits: &mut Bits) {
self.next_bits_width(bits, bits.bw()).unwrap();
}
#[must_use]
pub fn index(&mut self, len: usize) -> Option<usize> {
if len == 0 {
None
} else {
let w = if len >= (1 << (usize::BITS - 1)) {
usize::BITS as usize
} else {
len.next_power_of_two().trailing_zeros() as usize
};
let mut tmp = InlAwi::from_usize(0);
for _ in 0..64 {
self.next_bits_width(&mut tmp, w).unwrap();
let test_val = tmp.to_usize();
if test_val < len {
return Some(test_val);
}
}
Some(0)
}
}
#[must_use]
pub fn index_slice<'a, T>(&mut self, slice: &'a [T]) -> Option<&'a T> {
let inx = self.index(slice.len())?;
slice.get(inx)
}
#[must_use]
pub fn index_slice_mut<'a, T>(&mut self, slice: &'a mut [T]) -> Option<&'a mut T> {
let inx = self.index(slice.len())?;
slice.get_mut(inx)
}
pub fn linear_fuzz_step(&mut self, x: &mut Bits) {
let tmp0 = self.index(x.bw()).unwrap();
let tmp1 = self.index(x.bw().wrapping_add(1)).unwrap();
let r0 = min(tmp0, tmp1);
let r1 = max(tmp0, tmp1);
if self.next_bool() {
x.range_xor_(r0..r1).unwrap();
} else if self.next_bool() {
x.range_or_(r0..r1).unwrap();
} else {
x.range_and_(r0..r1).unwrap();
}
}
}
impl RngCore for StarRng {
fn next_u32(&mut self) -> u32 {
self.next_u32()
}
fn next_u64(&mut self) -> u64 {
self.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
for byte in dest {
*byte = self.next_u8();
}
}
}
impl SeedableRng for StarRng {
type Seed = [u8; 8];
fn from_seed(seed: Self::Seed) -> Self {
Self::new(u64::from_le_bytes(seed))
}
}