use super::super::rand::R;
pub trait Generator {
type Item;
fn generate(&self, r: &mut R) -> Self::Item;
fn map<O, F>(self, f: F) -> Map<Self, F>
where
Self: Sized,
F: Fn(Self::Item) -> O,
{
Map { generator: self, f }
}
fn such_that<F>(self, f: F) -> SuchThat<Self, F>
where
Self: Sized,
F: Fn(Self::Item) -> bool + Clone,
{
SuchThat {
retry: 1000,
generator: self,
f,
}
}
fn and<G>(self, other: G) -> And<Self, G>
where
Self: Sized,
{
And {
gen_a: self,
gen_b: other,
}
}
fn or<G>(self, other: G) -> Or<Self, G>
where
Self: Sized,
G: Generator<Item = Self::Item>,
{
Or {
gen_a: self,
gen_b: other,
}
}
fn into_boxed(self) -> BoxGenerator<Self::Item>
where
Self: Sized + 'static,
{
BoxGenerator(Box::new(self))
}
}
pub struct BoxGenerator<T>(pub(crate) Box<dyn Generator<Item = T>>);
impl<T> Generator for BoxGenerator<T> {
type Item = T;
fn generate(&self, r: &mut R) -> Self::Item {
self.0.generate(r)
}
fn into_boxed(self) -> BoxGenerator<Self::Item> {
self
}
}
#[derive(Clone)]
pub struct And<A, B> {
gen_a: A,
gen_b: B,
}
impl<A, B, T, U> Generator for And<A, B>
where
A: Generator<Item = T>,
B: Generator<Item = U>,
{
type Item = (T, U);
fn generate(&self, r: &mut R) -> Self::Item {
let a = self.gen_a.generate(&mut r.sub());
let b = self.gen_b.generate(&mut r.sub());
(a, b)
}
}
#[derive(Clone)]
pub struct Or<A, B> {
gen_a: A,
gen_b: B,
}
impl<A, B, T> Generator for Or<A, B>
where
A: Generator<Item = T>,
B: Generator<Item = T>,
{
type Item = T;
fn generate(&self, r: &mut R) -> Self::Item {
if r.bool() {
self.gen_a.generate(&mut r.sub())
} else {
self.gen_b.generate(&mut r.sub())
}
}
}
#[derive(Clone)]
pub struct Map<G, F> {
generator: G,
f: F,
}
impl<O, G: Generator, F> Generator for Map<G, F>
where
F: Fn(G::Item) -> O + Clone,
{
type Item = O;
fn generate(&self, r: &mut R) -> O {
let x = self.generator.generate(r);
(self.f)(x)
}
}
#[derive(Clone)]
pub struct SuchThat<G, F> {
retry: u32,
generator: G,
f: F,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct SuchThatRetryFailure;
impl<G: Generator, F> Generator for SuchThat<G, F>
where
F: Fn(&G::Item) -> bool + Clone,
{
type Item = G::Item;
fn generate(&self, r: &mut R) -> Self::Item {
let mut retry = self.retry;
loop {
let x = self.generator.generate(r);
if (self.f)(&x) {
break x;
}
if retry == 0 {
std::panic::panic_any(SuchThatRetryFailure);
} else {
retry -= 1;
}
}
}
}
#[derive(Clone)]
pub struct Constant<T>(T);
impl<T: Clone> Generator for Constant<T> {
type Item = T;
fn generate(&self, _: &mut R) -> Self::Item {
self.0.clone()
}
}
pub fn constant<T: Clone>(t: T) -> Constant<T> {
Constant(t)
}