use rand_core::impls::fill_bytes_via_next;
use rand_core::{Error, RngCore, SeedableRng};
pub mod large;
pub struct Linear16 {
s: u16,
}
pub struct Linear32 {
s: u32,
}
pub struct Linear64 {
s: u64,
}
macro_rules! impl_linear {
($t:ty) => {
fn get_bit(&mut self) -> u8 {
let output = self.s as u8 & 1u8;
self.clock();
output
}
fn get_bit_rev(&mut self) -> u8 {
let shift = std::mem::size_of::<$t>() * 8 - 1;
let output = (self.s >> shift) as u8 & 1u8;
self.clock_rev();
output
}
pub fn quick_bool(&mut self) -> bool {
if self.get_bit() == 1 {
true
} else {
false
}
}
pub fn quick_bool_rev(&mut self) -> bool {
if self.get_bit_rev() == 1 {
true
} else {
false
}
}
pub fn dump_state(&self) -> $t {
self.s
}
pub fn reverse_state(&mut self) {
self.s = self.s.reverse_bits();
}
pub fn inverse_state(&mut self) {
self.s = !self.s;
}
pub fn get_32bits(&mut self) -> u32 {
let mut output = 0u32;
for i in 0..32 {
output |= (self.get_bit() as u32) << i;
}
output
}
pub fn get_32bits_rev(&mut self) -> u32 {
let mut output = 0u32;
for i in 0..32 {
output |= (self.get_bit_rev() as u32) << (31 - i);
}
output
}
pub fn get_64bits(&mut self) -> u64 {
let mut output = 0u64;
for i in 0..64 {
output |= (self.get_bit() as u64) << i;
}
output
}
pub fn get_64bits_rev(&mut self) -> u64 {
let mut output = 0u64;
for i in 0..64 {
output |= (self.get_bit_rev() as u64) << (63 - i);
}
output
}
};
}
impl Linear16 {
pub fn clock(&mut self) {
let lsb = self.s & 1u16;
self.s >>= 1;
if lsb == 1 {
self.s ^= 0b1011_0100_0000_0000;
}
}
pub fn clock_rev(&mut self) {
let msb = self.s >> 15;
self.s <<= 1;
if msb == 1 {
self.s ^= 0b0000_0000_0010_1101;
}
}
impl_linear!(u16);
}
impl Linear32 {
pub fn clock(&mut self) {
let lsb = self.s & 1u32;
self.s >>= 1;
if lsb == 1 {
self.s ^= 0b1010_0011_0000_0000_0000_0000_0000_0000;
}
}
pub fn clock_rev(&mut self) {
let msb = self.s >> 31;
self.s <<= 1;
if msb == 1 {
self.s ^= 0b0000_0000_0000_0000_0000_0000_1100_0101;
}
}
impl_linear!(u32);
}
impl Linear64 {
pub fn clock(&mut self) {
let lsb = self.s & 1u64;
self.s >>= 1;
if lsb == 1 {
self.s ^= 0xD800000000000000;
}
}
pub fn clock_rev(&mut self) {
let msb = self.s >> 63;
self.s <<= 1;
if msb == 1 {
self.s ^= 0x000000000000001B;
}
}
impl_linear!(u64);
}
macro_rules! impl_core {
($name:ident) => {
impl RngCore for $name {
fn next_u32(&mut self) -> u32 {
self.get_32bits()
}
fn next_u64(&mut self) -> u64 {
self.get_64bits()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
fill_bytes_via_next(self, dest);
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
};
}
pub(crate) use impl_core;
impl_core!(Linear16);
impl_core!(Linear32);
impl_core!(Linear64);
macro_rules! impl_seedable {
($name:ident, $n:expr, $t:ty) => {
impl SeedableRng for $name {
type Seed = [u8; $n];
fn from_seed(seed: [u8; $n]) -> Self {
let mut all_zero = true;
for i in 0..$n {
if seed[i] != 0 {
all_zero = false;
break;
}
}
if all_zero {
return Self { s: <$t>::MAX };
}
let mut output: $t = 0;
for i in 0..$n {
output |= (seed[i] as $t) << (i * 8);
}
Self { s: output }
}
fn seed_from_u64(seed: u64) -> Self {
let output = seed as $t;
if output == 0 {
return Self { s: <$t>::MAX };
}
Self { s: output }
}
}
};
}
pub(crate) use impl_seedable;
impl_seedable!(Linear16, 2, u16);
impl_seedable!(Linear32, 4, u32);
impl_seedable!(Linear64, 8, u64);