pub use quickcheck::{Arbitrary, Gen, TestResult, Testable};
use std::{marker::PhantomData, ops::Range};
pub use rand;
use rand::{
distributions::uniform::SampleUniform, prelude::Distribution, seq::SliceRandom, Rng,
SeedableRng,
};
pub mod recursive;
pub struct Random {
pub rng: rand::rngs::SmallRng,
}
impl Random {
pub fn arbitrary<T: Arbitrary>(&self) -> T {
let mut qcg = Gen::new(100);
Arbitrary::arbitrary(&mut qcg)
}
pub fn new() -> Self {
Random {
rng: rand::rngs::SmallRng::from_entropy(),
}
}
pub fn from_seed(seed: u64) -> Self {
let seed: Vec<u8> = seed
.to_be_bytes()
.into_iter()
.chain(std::iter::repeat(0))
.take(32)
.collect();
Random {
rng: rand::rngs::SmallRng::from_seed(seed[0..32].try_into().unwrap()),
}
}
pub fn choose<'a, T>(&mut self, slice: &'a [T]) -> Option<&'a T> {
slice.choose(&mut self.rng)
}
pub fn gen<T>(&mut self) -> T
where
rand::distributions::Standard: rand::distributions::Distribution<T>,
{
self.rng.gen()
}
pub fn gen_range<T, R>(&mut self, range: R) -> T
where
T: rand::distributions::uniform::SampleUniform,
R: rand::distributions::uniform::SampleRange<T>,
{
self.rng.gen_range(range)
}
}
pub type Shrunk<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
pub trait Sample {
type Output;
fn generate(&mut self, g: &mut Random) -> Self::Output;
fn shrink(&self, _: Self::Output) -> Shrunk<'_, Self::Output> {
Box::new(std::iter::empty())
}
fn try_convert<T, I, F>(self, from: F, try_into: I) -> TryConvert<Self, F, I>
where
Self: Sized,
F: Fn(Self::Output) -> T,
I: Fn(T) -> Option<Self::Output>,
{
TryConvert {
inner: self,
from,
try_into,
}
}
fn zip<OS>(self, other: OS) -> Zip<Self, OS>
where
Self: Sized,
OS: Sample,
{
Zip { t: (self, other) }
}
fn chain_resample<F, RS>(self, transform: F, subsamples: usize) -> ChainResample<Self, F>
where
Self: Sized,
F: Fn(Self::Output) -> RS,
RS: Sample,
{
ChainResample {
supersampler: self,
transform,
subsamples,
}
}
}
#[derive(Clone)]
pub struct TryConvert<P, F, I> {
pub inner: P,
from: F,
try_into: I,
}
impl<P, F, I, T> Sample for TryConvert<P, F, I>
where
P: Sample,
F: Fn(P::Output) -> T,
I: Fn(T) -> Option<P::Output>,
{
type Output = T;
fn generate(&mut self, g: &mut Random) -> Self::Output {
(self.from)(P::generate(&mut self.inner, g))
}
fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
Box::new(
(self.try_into)(v)
.into_iter()
.flat_map(|v| P::shrink(&self.inner, v))
.map(&self.from),
)
}
}
#[derive(Clone)]
pub struct Zip<A, B> {
t: (A, B),
}
impl<A, B> Sample for Zip<A, B>
where
A: Sample,
B: Sample,
A::Output: Clone,
B::Output: Clone,
{
type Output = (A::Output, B::Output);
fn generate(&mut self, g: &mut Random) -> Self::Output {
self.t.generate(g)
}
fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
self.t.shrink(v)
}
}
macro_rules! replace_expr {
($_t:tt $sub:expr) => {
$sub
};
}
macro_rules! none_pad {
(($cur:ident) $($post: ident)*) => {
(Some($cur), $(replace_expr!($post None)),*)
};
($($pre:ident)+ ($cur:ident) $($post: ident)*) => {
($(replace_expr!($pre None)),*, Some($cur), $(replace_expr!($post None)),*)
};
}
macro_rules! shrink_tuple {
($v:ident () $($sample: ident)*) => {
let ($(casey::lower!($sample)),*) = $v.clone();
let r = std::iter::empty();
shrink_tuple!(r $v () ($($sample)*));
};
($r:ident $v:ident () ($cur:ident $($sample: ident)*)) => {
let (casey::lower!(ref $cur), $(casey::lower!(ref $sample)),*) = $v;
let r = $r.chain(
$cur.shrink(casey::lower!($cur).clone()).map(move |$cur| {
none_pad!(($cur) $($sample)*)
})
);
shrink_tuple!(r $v ($cur) ($($sample)*));
};
($r:ident $v:ident ($($pre:ident)+) ($cur:ident $($sample: ident)*)) => {
let ($(casey::lower!(ref $pre)),*, casey::lower!(ref $cur), $(casey::lower!(ref $sample)),*) = $v;
let r = $r.chain(
$cur.shrink(casey::lower!($cur).clone()).map(move |$cur| {
none_pad!($($pre)* ($cur) $($sample)*)
})
);
shrink_tuple!(r $v ($($pre)* $cur) ($($sample)*));
};
($r:ident $v:ident ($($pre:ident)*) ()) => {
let ($(casey::lower!($pre)),*) = $v;
return Box::new($r.map(move |($($pre),*)| {
($($pre.unwrap_or(casey::lower!($pre).clone())),*)
}))
};
}
macro_rules! sample_tuple {
($($name: ident),*) => {
impl<$($name),*> Sample for ($($name),*,)
where
$($name: Sample),*,
$($name::Output: Clone),*,
{
type Output = ($($name::Output),*,);
#[allow(non_snake_case)]
fn generate(&mut self, r: &mut Random) -> Self::Output {
let ($(casey::lower!($name)),*,) = self;
($(casey::lower!($name).generate(r)),*,)
}
#[allow(non_snake_case)]
fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
let ($($name),*,) = self;
shrink_tuple!(v () $($name)*);
}
}
}
}
impl<A> Sample for (A,)
where
A: Sample,
{
type Output = (A::Output,);
fn generate(&mut self, g: &mut Random) -> Self::Output {
(self.0.generate(g),)
}
fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
Box::new(self.0.shrink(v.0).map(|v| (v,)))
}
}
sample_tuple!(A, B);
sample_tuple!(A, B, C);
sample_tuple!(A, B, C, D);
sample_tuple!(A, B, C, D, E);
sample_tuple!(A, B, C, D, E, F);
sample_tuple!(A, B, C, D, E, F, G);
sample_tuple!(A, B, C, D, E, F, G, H);
#[derive(Clone, Debug)]
pub struct ChainResample<S, F> {
supersampler: S,
transform: F,
subsamples: usize,
}
#[derive(Clone, Debug)]
pub struct Chained<S, V> {
seed: S,
pub value: V,
}
impl<S, F, SS> Sample for ChainResample<S, F>
where
S: Sample,
S::Output: Clone,
SS: Sample + 'static,
F: Fn(S::Output) -> SS,
{
type Output = Chained<S::Output, SS::Output>;
fn generate(&mut self, g: &mut Random) -> Self::Output {
let seed = self.supersampler.generate(g);
let value = (self.transform)(seed.clone()).generate(g);
Chained { seed, value }
}
fn shrink(&self, v: Self::Output) -> Shrunk<Self::Output> {
Box::new(self.supersampler.shrink(v.seed).flat_map(|shrunk_seed| {
let mut g = Random::new();
let mut sampler = (self.transform)(shrunk_seed.clone());
(0..self.subsamples).map(move |_| Chained {
seed: shrunk_seed.clone(),
value: sampler.generate(&mut g),
})
}))
}
}
impl<T> Sample for Box<dyn Sample<Output = T>> {
type Output = T;
fn generate(&mut self, g: &mut Random) -> Self::Output {
self.as_mut().generate(g)
}
fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
self.as_ref().shrink(v)
}
}
impl<T> Sample for Box<dyn Sample<Output = T> + Send + Sync> {
type Output = T;
fn generate(&mut self, g: &mut Random) -> Self::Output {
self.as_mut().generate(g)
}
fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
self.as_ref().shrink(v)
}
}
#[derive(Debug, Clone)]
pub struct Chance(pub f32);
impl Sample for Chance {
type Output = bool;
fn generate(&mut self, g: &mut Random) -> Self::Output {
g.gen_range(0.0..1.0) < self.0
}
}
pub struct ArbitrarySampler<T> {
gen: Gen,
phantom: PhantomData<T>,
validate: fn(&T) -> bool,
}
impl<T> Clone for ArbitrarySampler<T> {
fn clone(&self) -> Self {
ArbitrarySampler {
gen: Gen::new(self.gen.size()),
phantom: self.phantom.clone(),
validate: self.validate.clone(),
}
}
}
impl<T: Arbitrary> Sample for ArbitrarySampler<T> {
type Output = T;
fn generate(&mut self, _: &mut Random) -> Self::Output {
for _ in 0..1000 {
let value = Arbitrary::arbitrary(&mut self.gen);
if (self.validate)(&value) {
return value;
}
}
panic!("could not find valid value after 1000 iterations")
}
fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
Arbitrary::shrink(&v)
}
}
pub fn arbitrary<T: Arbitrary>() -> ArbitrarySampler<T> {
ArbitrarySampler {
gen: Gen::new(100),
phantom: PhantomData,
validate: |_| true,
}
}
pub fn valid_f32() -> ArbitrarySampler<f32> {
ArbitrarySampler {
gen: Gen::new(100),
phantom: PhantomData,
validate: |f| !f.is_nan(),
}
}
pub fn valid_f64() -> ArbitrarySampler<f64> {
ArbitrarySampler {
gen: Gen::new(100),
phantom: PhantomData,
validate: |f| !f.is_nan(),
}
}
#[derive(Debug, Clone)]
pub struct Always<T>(pub T);
impl<T: Clone> Sample for Always<T> {
type Output = T;
fn generate(&mut self, _: &mut Random) -> Self::Output {
self.0.clone()
}
}
pub fn choice<T, II>(choices: II) -> Choice<T>
where
T: Clone + PartialEq,
II: IntoIterator<Item = T>,
{
Choice {
choices: choices.into_iter().collect(),
}
}
#[derive(Clone, Debug)]
pub struct Choice<T> {
pub choices: Vec<T>,
}
impl<T> Sample for Choice<T>
where
T: Clone + PartialEq,
{
type Output = T;
fn generate(&mut self, g: &mut Random) -> Self::Output {
g.choose(&self.choices).unwrap().clone()
}
fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
let ix = self.choices.iter().position(|el| el == &v).unwrap_or(0);
Box::new((0..ix).map(|shrunk_ix| self.choices[shrunk_ix].clone()))
}
}
pub fn sampler_choice<C, II>(choices: II) -> SamplerChoice<C>
where
II: IntoIterator<Item = C>,
C: Sample,
<C as Sample>::Output: Clone,
{
SamplerChoice {
choices: choices.into_iter().collect(),
}
}
#[derive(Clone, Debug)]
pub struct SamplerChoice<C> {
pub choices: Vec<C>,
}
impl<C> SamplerChoice<C> {
pub fn or(self, other: Self) -> Self {
Self {
choices: self
.choices
.into_iter()
.chain(other.choices.into_iter())
.collect(),
}
}
}
impl<C, T> Sample for SamplerChoice<C>
where
C: Sample<Output = T>,
T: Clone + 'static,
{
type Output = T;
fn generate(&mut self, g: &mut Random) -> Self::Output {
let ix = g.gen_range(0..self.choices.len());
self.choices[ix].generate(g)
}
fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
Box::new(self.choices.iter().flat_map(move |c| c.shrink(v.clone())))
}
}
impl<T, I> Sample for Range<T>
where
T: SampleUniform + Clone + PartialOrd + 'static,
Range<T>: IntoIterator<IntoIter = I>,
I: DoubleEndedIterator<Item = T> + 'static,
{
type Output = T;
fn generate(&mut self, g: &mut Random) -> Self::Output {
g.gen_range(self.clone())
}
fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
if self.start != v {
Box::new(
std::iter::once(self.start.clone())
.chain((self.start.clone()..v.clone()).into_iter().rev().take(1)),
)
} else {
Box::new(std::iter::empty())
}
}
}
#[derive(Clone, Debug)]
pub struct Regex {
pub dist: rand_regex::Regex,
pub re: regex::Regex,
}
impl Regex {
pub fn new(pattern: &str) -> Self {
Regex {
dist: rand_regex::Regex::compile(pattern, 100).unwrap(),
re: regex::Regex::new(pattern).unwrap(),
}
}
}
impl Sample for Regex {
type Output = String;
fn generate(&mut self, g: &mut Random) -> Self::Output {
self.dist.sample(&mut g.rng)
}
fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
let re = self.re.clone();
Box::new(Iterator::flat_map(0..v.len(), move |ix| {
let mut shrunk: String = String::with_capacity(v.len());
shrunk.push_str(&v[0..ix]);
shrunk.push_str(&v[ix..]);
if re.is_match(&shrunk) {
Some(shrunk)
} else {
None
}
}))
}
}
#[derive(Debug, Clone)]
pub struct VecSampler<S, I> {
pub length: S,
pub el: I,
}
impl<S, I, T> Sample for VecSampler<S, I>
where
S: Sample<Output = usize>,
I: Sample<Output = T>,
T: Clone + 'static,
{
type Output = Vec<T>;
fn generate(&mut self, g: &mut Random) -> Self::Output {
Iterator::map(0..self.length.generate(g), |_| self.el.generate(g)).collect()
}
fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
Box::new(self.length.shrink(v.len()).flat_map(move |new_len| {
assert!(new_len < v.len());
let gap = v.len() - new_len;
let iv = v.clone();
let iv2 = v.clone();
Iterator::map(0..new_len, move |cut| {
iv[0..cut]
.iter()
.chain(iv[cut + gap..].iter())
.cloned()
.collect()
})
.chain(Iterator::flat_map(0..v.len(), move |ix| {
let vref = iv2.clone();
let el = vref[ix].clone();
self.el.shrink(el).map(move |shrunk| {
let mut copy: Vec<T> = vref.clone();
copy[ix] = shrunk.clone();
copy.clone()
})
}))
}))
}
}
pub fn sample_all<S>(samplers: Vec<S>) -> SampleAll<S>
where
S: Sample,
{
SampleAll { samplers }
}
pub struct SampleAll<S> {
pub samplers: Vec<S>,
}
impl<S> Sample for SampleAll<S>
where
S: Sample,
S::Output: Clone,
{
type Output = Vec<S::Output>;
fn generate(&mut self, g: &mut Random) -> Self::Output {
self.samplers.iter_mut().map(|s| s.generate(g)).collect()
}
fn shrink(&self, v: Self::Output) -> Shrunk<'_, Self::Output> {
Box::new((0..self.samplers.len()).flat_map(move |ix| {
let mut updated = v.clone();
self.samplers[ix]
.shrink(updated[ix].clone())
.map(move |sv| {
updated[ix] = sv;
updated.clone()
})
}))
}
}
#[cfg(test)]
mod tests {}