#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct XorShift8(u8);
impl Default for XorShift8 {
fn default() -> Self {
Self::new_unchecked(Self::DEFAULT_SEED)
}
}
impl XorShift8 {
const DEFAULT_SEED: u8 = 0xDE;
#[cold]
#[inline]
const fn cold_path_result() -> Option<Self> {
None
}
#[cold]
#[inline]
#[allow(dead_code)]
const fn cold_path_default() -> Self {
Self::new_unchecked(Self::DEFAULT_SEED)
}
}
impl XorShift8 {
#[inline]
#[must_use]
pub const fn new(seed: u8) -> Option<Self> {
if seed == 0 {
Self::cold_path_result()
} else {
Some(Self(seed))
}
}
#[inline]
#[must_use]
pub const fn new_unchecked(seed: u8) -> Self {
debug_assert![seed != 0, "Seed must be non-zero"];
Self(seed)
}
#[inline(always)]
#[must_use]
pub const fn current_u8(&self) -> u8 {
self.0
}
#[inline]
#[must_use]
pub fn next_u8(&mut self) -> u8 {
let mut x = self.0;
x ^= x << 3;
x ^= x >> 4;
x ^= x << 2;
self.0 = x;
x
}
#[inline]
#[must_use]
pub const fn next_new(&self) -> Self {
let mut x = self.0;
x ^= x << 3;
x ^= x >> 4;
x ^= x << 2;
Self(x)
}
}
impl XorShift8 {
#[inline]
pub const fn new1_u8(seed: u8) -> Option<Self> {
Self::new(seed)
}
}
pub struct XorShift8Custom<const SH1: usize = 3, const SH2: usize = 4, const SH3: usize = 2>(u8);
impl<const SH1: usize, const SH2: usize, const SH3: usize> Default
for XorShift8Custom<SH1, SH2, SH3>
{
fn default() -> Self {
Self::new_unchecked(Self::DEFAULT_SEED)
}
}
impl<const SH1: usize, const SH2: usize, const SH3: usize> XorShift8Custom<SH1, SH2, SH3> {
const DEFAULT_SEED: u8 = 0xDE;
#[cold]
#[inline]
const fn cold_path_result() -> Option<Self> {
None
}
#[cold]
#[inline]
#[allow(dead_code)]
const fn cold_path_default() -> Self {
Self::new_unchecked(Self::DEFAULT_SEED)
}
}
impl<const SH1: usize, const SH2: usize, const SH3: usize> XorShift8Custom<SH1, SH2, SH3> {
#[inline]
pub const fn new(seed: u8) -> Option<Self> {
debug_assert![SH1 > 0 && SH1 <= 7];
debug_assert![SH2 > 0 && SH1 <= 7];
debug_assert![SH3 > 0 && SH1 <= 7];
if seed == 0 {
Self::cold_path_result()
} else {
Some(Self(seed))
}
}
#[inline]
#[must_use]
pub const fn new_unchecked(seed: u8) -> Self {
debug_assert![SH1 > 0 && SH1 <= 7];
debug_assert![SH2 > 0 && SH1 <= 7];
debug_assert![SH3 > 0 && SH1 <= 7];
debug_assert![seed != 0, "Seed must be non-zero"];
Self(seed)
}
#[inline(always)]
#[must_use]
pub const fn current_u8(&self) -> u8 {
self.0
}
#[inline]
pub fn next_u8(&mut self) -> u8 {
let mut x = self.0;
x ^= x << SH1;
x ^= x >> SH2;
x ^= x << SH3;
self.0 = x;
x
}
#[inline]
#[must_use]
pub const fn next_new(&self) -> Self {
let mut x = self.0;
x ^= x << SH1;
x ^= x >> SH2;
x ^= x << SH3;
Self(x)
}
}
impl<const SH1: usize, const SH2: usize, const SH3: usize> XorShift8Custom<SH1, SH2, SH3> {
#[inline]
pub const fn new1_u8(seed: u8) -> Option<Self> {
Self::new(seed)
}
}
#[cfg(feature = "rand_core")]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "rand_core")))]
mod impl_rand {
use super::{XorShift8, XorShift8Custom};
use rand_core::{Error, RngCore, SeedableRng};
impl RngCore for XorShift8 {
fn next_u32(&mut self) -> u32 {
u32::from_le_bytes([
self.next_u8(),
self.next_u8(),
self.next_u8(),
self.next_u8(),
])
}
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(),
])
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
for byte in dest {
*byte = self.next_u8();
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl SeedableRng for XorShift8 {
type Seed = [u8; 1];
fn from_seed(seed: Self::Seed) -> Self {
if seed[0] == 0 {
Self::cold_path_default()
} else {
Self::new_unchecked(seed[0])
}
}
}
impl<const SH1: usize, const SH2: usize, const SH3: usize> RngCore
for XorShift8Custom<SH1, SH2, SH3>
{
fn next_u32(&mut self) -> u32 {
u32::from_le_bytes([
self.next_u8(),
self.next_u8(),
self.next_u8(),
self.next_u8(),
])
}
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(),
])
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
for byte in dest {
*byte = self.next_u8();
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl<const SH1: usize, const SH2: usize, const SH3: usize> SeedableRng
for XorShift8Custom<SH1, SH2, SH3>
{
type Seed = [u8; 1];
fn from_seed(seed: Self::Seed) -> Self {
if seed[0] == 0 {
Self::cold_path_default()
} else {
Self::new_unchecked(seed[0])
}
}
}
}