use crate::{ConstInit, Own, Rand};
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_location!("num/prob/rand")]
#[doc = crate::_doc!(vendor: "Xabc")]
#[must_use]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Xabc {
a: u8,
b: u8,
c: u8,
x: u8,
}
impl Default for Xabc {
fn default() -> Self {
Self::INIT
}
}
impl ConstInit for Xabc {
const INIT: Self = Self::new(Self::DEFAULT_SEED);
}
impl Xabc {
#[doc(hidden)]
pub const DEFAULT_SEED: [u8; 3] = [0xDE, 0xFA, 0x17];
}
impl Xabc {
pub const fn new(seeds: [u8; 3]) -> Self {
let a = seeds[0];
let b = seeds[1];
let c = seeds[2];
let x = 1;
let a = a ^ c ^ x;
let b = b.wrapping_add(a);
let c = c.wrapping_add(b >> 1) ^ a;
Self { a, b, c, x }
}
pub const fn reseed(&mut self, seeds: [u8; 3]) {
self.a ^= seeds[0];
self.b ^= seeds[1];
self.c ^= seeds[2];
self.x += 1;
self.a = self.a ^ self.c ^ self.x;
self.b = self.b.wrapping_add(self.a);
self.c = self.c.wrapping_add(self.b >> 1) ^ self.a;
}
#[must_use]
pub const fn inner_state(self) -> [u8; 4] {
[self.a, self.b, self.c, self.x]
}
pub const fn from_state(state: [u8; 4]) -> Self {
Self { a: state[0], b: state[1], c: state[2], x: state[3] }
}
#[must_use]
pub const fn current_u8(&self) -> u8 {
self.c
}
#[must_use]
pub const fn next_u8(&mut self) -> u8 {
self.x = self.x.wrapping_add(1);
self.a = self.a ^ self.c ^ self.x;
self.b = self.b.wrapping_add(self.a);
self.c = self.c.wrapping_add(self.b >> 1) ^ self.a;
self.c
}
pub const fn peek_next_state(&self) -> Self {
let [mut a, mut b, mut c, mut x] = [self.a, self.b, self.c, self.x];
x += 1;
a = a ^ c ^ x;
b = b.wrapping_add(a);
c = c.wrapping_add(b >> 1) ^ a;
Self { a, b, c, 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)
}
}
impl Xabc {
pub const fn new3_u8(seeds: [u8; 3]) -> Self {
Self::new(seeds)
}
}
impl Rand for Xabc {
const RAND_OUTPUT_BITS: u32 = 8;
const RAND_STATE_BITS: u32 = 32;
fn rand_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(),
])
}
fn rand_next_u32(&mut self) -> u32 {
u32::from_le_bytes([self.next_u8(), self.next_u8(), self.next_u8(), self.next_u8()])
}
fn rand_fill_bytes(&mut self, dest: &mut [u8]) {
for byte in dest {
*byte = self.next_u8();
}
}
}
#[cfg(feature = "dep_rand_core")]
#[cfg_attr(nightly_doc, doc(cfg(feature = "dep_rand_core")))]
mod impl_rand {
use super::{Rand, Xabc};
use crate::_dep::rand_core::{SeedableRng, TryRng};
impl TryRng for Xabc {
type Error = crate::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
Ok(self.rand_next_u32())
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
Ok(self.rand_next_u64())
}
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
self.rand_fill_bytes(dst);
Ok(())
}
}
impl SeedableRng for Xabc {
type Seed = [u8; 3];
fn from_seed(seed: Self::Seed) -> Self {
Self::new(seed)
}
}
}