use crate::{_xorshift_basis, Infallible, InfallibleResult, RandQualities, RandSeedable, RandTry};
use crate::{ConstInit, Own, whilst};
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_meta!{location("num/prob/rand")}]
#[must_use]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct XorShift8<const A: usize = 3, const B: usize = 4, const C: usize = 2>(u8);
impl<const A: usize, const B: usize, const C: usize> Default for XorShift8<A, B, C> {
fn default() -> Self {
Self::new_unchecked(Self::DEFAULT_SEED)
}
}
impl<const A: usize, const B: usize, const C: usize> ConstInit for XorShift8<A, B, C> {
const INIT: Self = Self::new_unchecked(Self::DEFAULT_SEED);
}
impl<const A: usize, const B: usize, const C: usize> XorShift8<A, B, C> {
#[doc(hidden)]
pub const DEFAULT_SEED: u8 = 0xDE;
#[cold] #[allow(dead_code)] #[rustfmt::skip]
const fn cold_path_default() -> Self { Self::new_unchecked(Self::DEFAULT_SEED) }
}
impl<const A: usize, const B: usize, const C: usize> XorShift8<A, B, C> {
pub const fn new(seed: u8) -> Self {
debug_assert![A > 0 && A <= 7];
debug_assert![B > 0 && A <= 7];
debug_assert![C > 0 && A <= 7];
if seed == 0 { Self::cold_path_default() } else { Self(seed) }
}
pub const fn new_unchecked(seed: u8) -> Self {
debug_assert![A > 0 && A <= 7];
debug_assert![B > 0 && A <= 7];
debug_assert![C > 0 && A <= 7];
debug_assert![seed != 0, "Seed must be non-zero"];
Self(seed)
}
#[must_use]
pub const fn inner_state(self) -> u8 {
self.0
}
pub const fn from_state(state: u8) -> Self {
Self(state)
}
#[must_use]
pub const fn current_u8(&self) -> u8 {
self.0
}
pub const fn next_u8(&mut self) -> u8 {
let mut x = self.0;
_xorshift_basis!(x, 0, (A, B, C));
self.0 = x;
x
}
pub const fn peek_next_state(&self) -> Self {
let mut x = self.0;
_xorshift_basis!(x, 0, (A, B, C));
Self(x)
}
pub const fn own_next_u8(self) -> Own<Self, u8> {
let s = self.peek_next_state();
let v = s.current_u8();
Own::new(s, v)
}
pub const fn fill_bytes(&mut self, buffer: &mut [u8]) {
whilst! { i in 0..buffer.len(); {
buffer[i] = self.next_u8();
}}
}
}
impl<const A: usize, const B: usize, const C: usize> XorShift8<A, B, C> {
pub const fn new1_u8(seed: u8) -> Self {
Self::new(seed)
}
pub const fn next_u16(&mut self) -> u16 {
u16::from_le_bytes([self.next_u8(), self.next_u8()])
}
pub const fn next_u32(&mut self) -> u32 {
u32::from_le_bytes([self.next_u8(), self.next_u8(), self.next_u8(), self.next_u8()])
}
pub const fn next_u64(&mut self) -> u64 {
u64::from_le_bytes([
self.next_u8(),
self.next_u8(),
self.next_u8(),
self.next_u8(),
self.next_u8(),
self.next_u8(),
self.next_u8(),
self.next_u8(),
])
}
}
crate::items! {
impl<const A: usize, const B: usize, const C: usize> RandTry for XorShift8<A, B, C> {
type Error = Infallible;
const RAND_OUTPUT_BITS: u32 = 8;
const RAND_STATE_BITS: u32 = 8;
const RAND_QUALITIES: RandQualities = RandQualities::WEAK_PRNG;
fn rand_try_next_u8(&mut self) -> InfallibleResult<u8> { Ok(self.next_u8()) }
fn rand_try_next_u16(&mut self) -> InfallibleResult<u16> { Ok(self.next_u16()) }
fn rand_try_next_u32(&mut self) -> InfallibleResult<u32> { Ok(self.next_u32()) }
fn rand_try_next_u64(&mut self) -> InfallibleResult<u64> { Ok(self.next_u64()) }
fn rand_try_fill_bytes(&mut self, buffer: &mut [u8]) -> InfallibleResult<()> {
self.fill_bytes(buffer); Ok(())
}
}
impl<const A: usize, const B: usize, const C: usize> RandSeedable for XorShift8<A, B, C> {
type RandSeed = [u8; 1];
#[inline(always)]
fn rand_from_seed(seed: Self::RandSeed) -> Self { Self::new(seed[0]) }
}
}
crate::__impl_dep_rand_core!(XorShift8<const A: usize, const B: usize, const C: usize>);