use arbitrary::Unstructured;
use rand::RngExt;
const ALPHANUM_CHARS: &[char; 62] = &[
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
'5', '6', '7', '8', '9',
];
#[derive(Debug, thiserror::Error)]
pub enum ResponseError {
#[error("randomness source attempted to choose from an empty range")]
EmptyChoose,
#[error("randomness source exhausted or produced invalid data")]
Exhausted,
#[error("invalid format: {0}")]
InvalidFormat(String),
}
pub trait RandomProvider {
fn gen_bool(&mut self) -> Result<bool, ResponseError>;
fn gen_i32_range(&mut self, min: i32, max: i32) -> Result<i32, ResponseError>;
fn gen_usize_range(&mut self, min: usize, max: usize) -> Result<usize, ResponseError>;
fn gen_f64_range(&mut self, min: f64, max: f64) -> Result<f64, ResponseError>;
fn gen_alphanumeric_char(&mut self) -> Result<char, ResponseError>;
fn choose_index(&mut self, len: usize) -> Result<usize, ResponseError>;
fn ratio(&mut self, numerator: u32, denominator: u32) -> Result<bool, ResponseError>;
}
impl RandomProvider for Unstructured<'_> {
fn gen_bool(&mut self) -> Result<bool, ResponseError> {
self.arbitrary::<bool>()
.map_err(|_| ResponseError::Exhausted)
}
fn gen_i32_range(&mut self, min: i32, max: i32) -> Result<i32, ResponseError> {
self.int_in_range(min..=max)
.map_err(|_| ResponseError::Exhausted)
}
fn gen_usize_range(&mut self, min: usize, max: usize) -> Result<usize, ResponseError> {
self.int_in_range(min..=max)
.map_err(|_| ResponseError::Exhausted)
}
fn gen_f64_range(&mut self, min: f64, max: f64) -> Result<f64, ResponseError> {
let raw: u32 = self.arbitrary().map_err(|_| ResponseError::Exhausted)?;
let fraction = (raw as f64) / (u32::MAX as f64); Ok(min + fraction * (max - min))
}
fn gen_alphanumeric_char(&mut self) -> Result<char, ResponseError> {
self.choose(ALPHANUM_CHARS)
.map_err(|_| ResponseError::Exhausted)
.copied()
}
fn choose_index(&mut self, len: usize) -> Result<usize, ResponseError> {
self.choose_index(len)
.map_err(|_| ResponseError::EmptyChoose)
}
fn ratio(&mut self, numerator: u32, denominator: u32) -> Result<bool, ResponseError> {
self.ratio(numerator, denominator)
.map_err(|_| ResponseError::Exhausted)
}
}
pub struct RandProvider<R>(pub R);
impl<R: rand::Rng> RandomProvider for RandProvider<R> {
fn gen_bool(&mut self) -> Result<bool, ResponseError> {
Ok(self.0.random_bool(0.5))
}
fn gen_i32_range(&mut self, min: i32, max: i32) -> Result<i32, ResponseError> {
Ok(self.0.random_range(min..=max))
}
fn gen_usize_range(&mut self, min: usize, max: usize) -> Result<usize, ResponseError> {
Ok(self.0.random_range(min..=max))
}
fn gen_f64_range(&mut self, min: f64, max: f64) -> Result<f64, ResponseError> {
Ok(self.0.random_range(min..=max))
}
fn gen_alphanumeric_char(&mut self) -> Result<char, ResponseError> {
Ok(self.0.sample(rand::distr::Alphanumeric) as char)
}
fn choose_index(&mut self, len: usize) -> Result<usize, ResponseError> {
if len == 0 {
return Err(ResponseError::EmptyChoose);
}
Ok(self.0.random_range(0..len))
}
fn ratio(&mut self, numerator: u32, denominator: u32) -> Result<bool, ResponseError> {
Ok(self.0.random_ratio(numerator, denominator))
}
}