#![forbid(unsafe_code)]
use std::fmt::{self, Display};
use std::num::NonZeroU64;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ExactBenchConfigError {
EmptyCorpus,
InvalidRangeWidth {
min: i16,
max: i16,
width: i32,
},
UnorderedRange {
min: i16,
max: i16,
},
}
impl Display for ExactBenchConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::EmptyCorpus => f.write_str("random input corpus must be nonempty"),
Self::InvalidRangeWidth { min, max, width } => {
write!(
f,
"random integer range {min}..={max} produced invalid sampling width {width}"
)
}
Self::UnorderedRange { min, max } => {
write!(f, "random integer range must be ordered: {min}..={max}")
}
}
}
}
impl std::error::Error for ExactBenchConfigError {}
#[derive(Clone, Copy)]
#[must_use]
pub struct I16Range {
min: i16,
width: NonZeroU64,
}
impl I16Range {
pub fn new(min: i16, max: i16) -> Result<Self, ExactBenchConfigError> {
if min > max {
return Err(ExactBenchConfigError::UnorderedRange { min, max });
}
let raw_width = i32::from(max) - i32::from(min) + 1;
let width =
u64::try_from(raw_width).map_err(|_| ExactBenchConfigError::InvalidRangeWidth {
min,
max,
width: raw_width,
})?;
let width = NonZeroU64::new(width).ok_or(ExactBenchConfigError::InvalidRangeWidth {
min,
max,
width: raw_width,
})?;
Ok(Self { min, width })
}
}
#[must_use]
pub struct SplitMix64 {
state: u64,
}
impl SplitMix64 {
pub const fn new(state: u64) -> Self {
Self { state }
}
const fn next_u64(&mut self) -> u64 {
self.state = self.state.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = self.state;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
#[allow(clippy::cast_possible_truncation)]
#[must_use]
pub fn next_i16(&mut self, range: I16Range) -> i16 {
let offset = (self.next_u64() % range.width.get()) as i32;
let value = i32::from(range.min) + offset;
value as i16
}
}