use std::convert::Infallible;
use rand::Rng;
use rand::SeedableRng;
use rand::rand_core::TryRng;
use rand::rngs::StdRng;
use crate::generators::{Generator, PrintableGenerator, TestCase, binary, integers};
use crate::pretty::PrettyPrinter;
pub struct RandomsGenerator {
use_true_random: bool,
}
impl RandomsGenerator {
pub fn use_true_random(mut self, use_true_random: bool) -> Self {
self.use_true_random = use_true_random;
self
}
}
impl Generator<HegelRandom> for RandomsGenerator {
fn do_draw(&self, tc: &TestCase) -> HegelRandom {
if self.use_true_random {
let seed: u64 = integers().do_draw(tc);
HegelRandom {
source: RandomSource::True(Box::new(StdRng::seed_from_u64(seed))),
}
} else {
HegelRandom {
source: RandomSource::Artificial(tc.clone(), None),
}
}
}
}
impl PrintableGenerator<HegelRandom> for RandomsGenerator {
fn do_draw_and_print(&self, tc: &TestCase, printer: &mut PrettyPrinter) -> HegelRandom {
if self.use_true_random {
let seed: u64 = integers().do_draw(tc);
printer.text(&format!("HegelRandom {{ seed: {seed} }}"));
return HegelRandom {
source: RandomSource::True(Box::new(StdRng::seed_from_u64(seed))),
};
}
printer.begin_group(1, "HegelRandom { consumed: [");
let slot = printer.clone();
printer.end_group("] }");
HegelRandom {
source: RandomSource::Artificial(
tc.clone(),
Some(RngPrintSlot {
printer: slot,
recorded: 0,
}),
),
}
}
}
#[derive(Debug)]
struct RngPrintSlot {
printer: PrettyPrinter,
recorded: usize,
}
impl RngPrintSlot {
fn record(&mut self, value: std::fmt::Arguments<'_>) {
if self.recorded > 0 {
self.printer.text(",");
self.printer.breakable(" ");
}
self.recorded += 1;
self.printer.text(&value.to_string());
}
}
#[derive(Debug)]
pub struct HegelRandom {
source: RandomSource,
}
#[derive(Debug)]
enum RandomSource {
Artificial(TestCase, Option<RngPrintSlot>),
True(Box<StdRng>),
}
impl TryRng for HegelRandom {
type Error = Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
Ok(match &mut self.source {
RandomSource::Artificial(tc, slot) => {
let value: u32 = integers().do_draw(tc);
if let Some(slot) = slot {
slot.record(format_args!("{value}"));
}
value
}
RandomSource::True(rng) => rng.next_u32(),
})
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
Ok(match &mut self.source {
RandomSource::Artificial(tc, slot) => {
let value: u64 = integers().do_draw(tc);
if let Some(slot) = slot {
slot.record(format_args!("{value}"));
}
value
}
RandomSource::True(rng) => rng.next_u64(),
})
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
match &mut self.source {
RandomSource::Artificial(tc, slot) => {
let bytes: Vec<u8> = binary()
.min_size(dest.len())
.max_size(dest.len())
.do_draw(tc);
dest.copy_from_slice(&bytes);
if let Some(slot) = slot {
slot.record(format_args!("{bytes:?}"));
}
}
RandomSource::True(rng) => rng.fill_bytes(dest),
}
Ok(())
}
}
pub fn randoms() -> RandomsGenerator {
RandomsGenerator {
use_true_random: false,
}
}