use crate::{Driver, TypeGenerator, TypeGeneratorWithParams, TypeValueGenerator, ValueGenerator};
#[cfg(feature = "either")]
use either::Either;
macro_rules! impl_either {
(
$generator:ident,
$ty:ident,
$A:ident,
$with_a:ident,
$map_a:ident,
$B:ident,
$with_b:ident,
$map_b:ident
) => {
#[derive(Debug, Clone)]
pub struct $generator<$A, $B, Selector> {
a: $A,
b: $B,
selector: Selector,
}
impl<$A: ValueGenerator, $B: ValueGenerator, Selector: ValueGenerator<Output = bool>>
$generator<$A, $B, Selector>
{
pub fn $with_a<Gen: ValueGenerator<Output = $A::Output>>(
self,
gen: Gen,
) -> $generator<Gen, $B, Selector> {
$generator {
a: gen,
b: self.b,
selector: self.selector,
}
}
pub fn $map_a<Gen: ValueGenerator<Output = $A::Output>, F: Fn($A) -> Gen>(
self,
map: F,
) -> $generator<Gen, $B, Selector> {
$generator {
a: map(self.a),
b: self.b,
selector: self.selector,
}
}
pub fn $with_b<Gen: ValueGenerator<Output = $B::Output>>(
self,
gen: Gen,
) -> $generator<$A, Gen, Selector> {
$generator {
a: self.a,
b: gen,
selector: self.selector,
}
}
pub fn $map_b<Gen: ValueGenerator<Output = $B::Output>, F: Fn($B) -> Gen>(
self,
map: F,
) -> $generator<$A, Gen, Selector> {
$generator {
a: self.a,
b: map(self.b),
selector: self.selector,
}
}
pub fn with_selector<Gen: ValueGenerator<Output = bool>>(
self,
selector: Gen,
) -> $generator<$A, $B, Gen> {
$generator {
a: self.a,
b: self.b,
selector,
}
}
pub fn map_selector<Gen: ValueGenerator<Output = bool>, F: Fn(Selector) -> Gen>(
self,
map: F,
) -> $generator<$A, $B, Gen> {
$generator {
a: self.a,
b: self.b,
selector: map(self.selector),
}
}
}
impl<$A: ValueGenerator, $B: ValueGenerator, Selector: ValueGenerator<Output = bool>>
ValueGenerator for $generator<$A, $B, Selector>
{
type Output = $ty<$A::Output, $B::Output>;
fn generate<D: Driver>(&self, driver: &mut D) -> Option<Self::Output> {
Some(if self.selector.generate(driver)? {
$ty::$A(self.a.generate(driver)?)
} else {
$ty::$B(self.b.generate(driver)?)
})
}
fn mutate<D: Driver>(&self, driver: &mut D, value: &mut Self::Output) -> Option<()> {
#[allow(clippy::redundant_pattern_matching)]
let prev_selection = match value {
$ty::$A(_) => true,
$ty::$B(_) => false,
};
let mut new_selection = prev_selection;
self.selector.mutate(driver, &mut new_selection)?;
if prev_selection == new_selection {
match value {
$ty::$A(value) => self.a.mutate(driver, value),
$ty::$B(value) => self.b.mutate(driver, value),
}
} else {
if new_selection {
*value = $ty::$A(self.a.generate(driver)?);
} else {
*value = $ty::$B(self.b.generate(driver)?);
}
Some(())
}
}
}
impl<$A: TypeGenerator, $B: TypeGenerator> TypeGenerator for $ty<$A, $B> {
#[inline]
fn generate<D: Driver>(driver: &mut D) -> Option<Self> {
crate::gen_with::<Self>().generate(driver)
}
#[inline]
fn mutate<D: Driver>(&mut self, driver: &mut D) -> Option<()> {
crate::gen_with::<Self>().mutate(driver, self)
}
}
impl<$A: TypeGenerator, $B: TypeGenerator> TypeGeneratorWithParams for $ty<$A, $B> {
type Output = $generator<
TypeValueGenerator<$A>,
TypeValueGenerator<$B>,
TypeValueGenerator<bool>,
>;
fn gen_with() -> Self::Output {
$generator {
a: Default::default(),
b: Default::default(),
selector: Default::default(),
}
}
}
};
}
impl_either!(ResultGenerator, Result, Ok, ok, map_ok, Err, err, map_err);
#[cfg(feature = "either")]
impl_either!(
EitherGenerator,
Either,
Left,
left,
map_left,
Right,
right,
map_right
);
pub struct OptionGenerator<V, Selector> {
value: V,
selector: Selector,
}
impl<V: ValueGenerator, Selector: ValueGenerator<Output = bool>> OptionGenerator<V, Selector> {
pub fn value<Gen: ValueGenerator<Output = V::Output>>(
self,
value: Gen,
) -> OptionGenerator<Gen, Selector> {
OptionGenerator {
value,
selector: self.selector,
}
}
pub fn map_value<Gen: ValueGenerator<Output = V::Output>, F: Fn(V) -> Gen>(
self,
map: F,
) -> OptionGenerator<Gen, Selector> {
OptionGenerator {
value: map(self.value),
selector: self.selector,
}
}
pub fn selector<Gen: ValueGenerator<Output = bool>>(
self,
selector: Gen,
) -> OptionGenerator<V, Gen> {
OptionGenerator {
value: self.value,
selector,
}
}
pub fn map_selector<Gen: ValueGenerator<Output = bool>, F: Fn(Selector) -> Gen>(
self,
map: F,
) -> OptionGenerator<V, Gen> {
OptionGenerator {
value: self.value,
selector: map(self.selector),
}
}
}
impl<V: ValueGenerator, Selector: ValueGenerator<Output = bool>> ValueGenerator
for OptionGenerator<V, Selector>
{
type Output = Option<V::Output>;
fn generate<D: Driver>(&self, driver: &mut D) -> Option<Self::Output> {
Some(if self.selector.generate(driver)? {
Some(self.value.generate(driver)?)
} else {
None
})
}
fn mutate<D: Driver>(&self, driver: &mut D, value: &mut Self::Output) -> Option<()> {
let prev_selection = value.is_some();
let mut new_selection = prev_selection;
self.selector.mutate(driver, &mut new_selection)?;
if prev_selection == new_selection {
match value {
Some(value) => self.value.mutate(driver, value),
None => Some(()),
}
} else {
if new_selection {
*value = Some(self.value.generate(driver)?);
} else {
*value = None;
}
Some(())
}
}
}
impl<V: TypeGenerator> TypeGenerator for Option<V> {
#[inline]
fn generate<D: Driver>(driver: &mut D) -> Option<Self> {
crate::gen_with::<Self>().generate(driver)
}
#[inline]
fn mutate<D: Driver>(&mut self, driver: &mut D) -> Option<()> {
crate::gen_with::<Self>().mutate(driver, self)
}
}
impl<V: TypeGenerator> TypeGeneratorWithParams for Option<V> {
type Output = OptionGenerator<TypeValueGenerator<V>, TypeValueGenerator<bool>>;
fn gen_with() -> Self::Output {
OptionGenerator {
value: Default::default(),
selector: Default::default(),
}
}
}
#[test]
fn result_test() {
let _ = generator_test!(gen::<Result<u8, u8>>());
}
#[test]
fn option_test() {
let _ = generator_test!(gen::<Option<u8>>());
}