use crate::{Cast, ConstInit, Own};
use crate::{Infallible, InfallibleResult, RandQualities, RandSeedable, RandTry};
#[doc = crate::_tags!(rand)]
#[doc = concat!["A 16-bit ", crate::_ABBR_LCG!(), " ", crate::_ABBR_PRNG!(), "."]]
#[doc = crate::_doc_meta!{location("num/prob/rand")}]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Lcg16(u16);
impl Default for Lcg16 {
fn default() -> Self {
Self::INIT
}
}
impl ConstInit for Lcg16 {
const INIT: Self = Self::new(Self::DEFAULT_SEED);
}
impl Lcg16 {
#[doc(hidden)]
pub const DEFAULT_SEED: u16 = 0xDEFA;
const MUL: u16 = 25173;
const INC: u16 = 13849;
const MOD: u16 = 65535;
}
impl Lcg16 {
#[must_use]
pub const fn new(seed: u16) -> Self {
Self(seed)
}
pub const fn reseed(&mut self, seed: u16) {
self.0 = seed;
}
#[must_use]
pub const fn inner_state(self) -> u16 {
self.0
}
pub const fn from_state(state: u16) -> Self {
Self(state)
}
#[must_use]
pub const fn current_u16(&self) -> u16 {
self.0
}
#[must_use]
pub const fn next_u16(&mut self) -> u16 {
self.0 = (Self::MUL.wrapping_mul(self.0).wrapping_add(Self::INC)) & Self::MOD;
self.0
}
#[must_use]
pub const fn peek_next_state(&self) -> Self {
let x = (Self::MUL.wrapping_mul(self.0).wrapping_add(Self::INC)) & Self::MOD;
Self(x)
}
pub const fn own_next_u16(self) -> Own<Self, u16> {
let s = self.peek_next_state();
let v = s.current_u16();
Own::new(s, v)
}
pub const fn fill_bytes(&mut self, buffer: &mut [u8]) {
let mut i = 0;
while i < buffer.len() {
let random_u16 = self.next_u16();
let bytes = random_u16.to_le_bytes();
let remaining = buffer.len() - i;
if remaining >= 2 {
buffer[i] = bytes[0];
buffer[i + 1] = bytes[1];
i += 2;
} else {
buffer[i] = bytes[0];
i += 1;
}
}
}
}
impl Lcg16 {
pub const fn new1_u16(seed: u16) -> Self {
Self::new(seed)
}
#[must_use]
pub const fn new2_u8(seeds: [u8; 2]) -> Self {
Self::new(u16::from_le_bytes(seeds))
}
pub const fn next_u32(&mut self) -> u32 {
Cast::<u32>::from_u16_le([self.next_u16(), self.next_u16()])
}
pub const fn next_u64(&mut self) -> u64 {
Cast::<u64>::from_u16_le([
self.next_u16(),
self.next_u16(),
self.next_u16(),
self.next_u16(),
])
}
}
crate::items! {
impl RandTry for Lcg16 {
type Error = Infallible;
const RAND_OUTPUT_BITS: u32 = 64;
const RAND_STATE_BITS: u32 = 64;
const RAND_QUALITIES: RandQualities = RandQualities::WEAK_PRNG;
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 RandSeedable for Lcg16 {
type RandSeed = [u8; 2];
#[inline(always)]
fn rand_from_seed(seed: Self::RandSeed) -> Self { Self::new(u16::from_le_bytes(seed)) }
}
}
crate::__impl_dep_rand_core!(Lcg16);