use rand::SeedableRng;
use rand::prelude::StdRng;
use rand::rngs::SysRng;
#[derive(Debug, Default, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
pub enum RngSource {
#[default]
Default,
Seed(u64),
Rng(StdRng),
}
impl From<RngSource> for StdRng {
fn from(source: RngSource) -> Self {
match source {
RngSource::Default => StdRng::try_from_rng(&mut SysRng).unwrap(),
RngSource::Rng(rng) => rng,
RngSource::Seed(seed) => StdRng::seed_from_u64(seed),
}
}
}
impl From<u64> for RngSource {
fn from(seed: u64) -> Self {
Self::Seed(seed)
}
}
impl From<StdRng> for RngSource {
fn from(rng: StdRng) -> Self {
Self::Rng(rng)
}
}
impl From<&mut StdRng> for RngSource {
fn from(rng: &mut StdRng) -> Self {
Self::Rng(rng.fork())
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub enum SizeConfig {
#[default]
Default,
Ratio(f64),
Fixed(usize),
}
impl SizeConfig {
pub fn source() -> Self {
Self::Default
}
pub fn resolve(self, source_size: usize) -> usize {
match self {
SizeConfig::Default => source_size,
SizeConfig::Ratio(ratio) => {
assert!(ratio >= 0.0, "Ratio must be positive: {ratio}");
((source_size as f64) * ratio) as usize
}
SizeConfig::Fixed(size) => size,
}
}
}
impl From<usize> for SizeConfig {
fn from(size: usize) -> Self {
Self::Fixed(size)
}
}
impl From<f64> for SizeConfig {
fn from(ratio: f64) -> Self {
Self::Ratio(ratio)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::SeedableRng;
#[test]
fn test_rng_source_default() {
let rng_source: RngSource = Default::default();
assert_eq!(&rng_source, &RngSource::Default);
assert_eq!(&rng_source, &RngSource::default());
let _rng: StdRng = rng_source.into();
}
#[test]
fn test_rng_source_seed() {
let rng_source = RngSource::from(42);
assert_eq!(&rng_source, &RngSource::Seed(42));
let rng: StdRng = rng_source.into();
let expected = StdRng::seed_from_u64(42);
assert_eq!(rng, expected);
}
#[test]
fn test_rng_source_rng() {
{
let original = StdRng::seed_from_u64(42);
let rng_source = RngSource::from(original);
let rng: StdRng = rng_source.into();
let original = StdRng::seed_from_u64(42);
assert_eq!(rng, original);
}
{
let mut original = StdRng::seed_from_u64(42);
let mut rng = StdRng::seed_from_u64(42);
let rng_forked = rng.fork();
let rng_source = RngSource::from(&mut original);
assert_eq!(original, rng);
let rng: StdRng = rng_source.into();
assert_eq!(rng, rng_forked);
}
}
#[test]
fn test_size_config() {
assert_eq!(SizeConfig::default(), SizeConfig::Default);
assert_eq!(SizeConfig::from(42), SizeConfig::Fixed(42));
assert_eq!(SizeConfig::from(1.5), SizeConfig::Ratio(1.5));
assert_eq!(SizeConfig::source(), SizeConfig::Default);
assert_eq!(SizeConfig::source().resolve(50), 50);
}
}