use crate::PartialOp;
use quickcheck::{empty_shrinker, Arbitrary, Gen};
use rand::{rngs::SmallRng, Rng, SeedableRng};
use std::{io, marker::PhantomData, ops::Deref};
#[derive(Clone, Debug)]
pub struct PartialWithErrors<GE> {
items: Vec<PartialOp>,
_marker: PhantomData<GE>,
}
impl<GE> IntoIterator for PartialWithErrors<GE> {
type Item = PartialOp;
type IntoIter = ::std::vec::IntoIter<PartialOp>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl<GE> Deref for PartialWithErrors<GE> {
type Target = [PartialOp];
fn deref(&self) -> &Self::Target {
self.items.deref()
}
}
pub trait GenError: Clone + Default + Send {
fn gen_error(&mut self, g: &mut Gen) -> Option<io::ErrorKind>;
}
#[derive(Clone, Debug, Default)]
pub struct GenInterrupted;
#[derive(Clone, Debug, Default)]
pub struct GenWouldBlock;
#[derive(Clone, Debug, Default)]
pub struct GenInterruptedWouldBlock;
macro_rules! impl_gen_error {
($id: ident, [$($errors:expr),+]) => {
impl GenError for $id {
fn gen_error(&mut self, g: &mut Gen) -> Option<io::ErrorKind> {
let mut rng = SmallRng::from_entropy();
if rng.gen_ratio(1, 5) {
Some(g.choose(&[$($errors,)*]).unwrap().clone())
} else {
None
}
}
}
}
}
impl_gen_error!(GenInterrupted, [io::ErrorKind::Interrupted]);
impl_gen_error!(GenWouldBlock, [io::ErrorKind::WouldBlock]);
impl_gen_error!(
GenInterruptedWouldBlock,
[io::ErrorKind::Interrupted, io::ErrorKind::WouldBlock]
);
#[derive(Clone, Debug, Default)]
pub struct GenNoErrors;
impl GenError for GenNoErrors {
fn gen_error(&mut self, _g: &mut Gen) -> Option<io::ErrorKind> {
None
}
}
impl<GE> Arbitrary for PartialWithErrors<GE>
where
GE: GenError + 'static,
{
fn arbitrary(g: &mut Gen) -> Self {
let size = g.size();
let mut gen_error = GE::default();
let items: Vec<_> = (0..size)
.map(|_| {
match gen_error.gen_error(g) {
Some(err) => PartialOp::Err(err),
None => {
let mut rng = SmallRng::from_entropy();
PartialOp::Limited(rng.gen_range(1..size))
}
}
})
.collect();
PartialWithErrors {
items,
_marker: PhantomData,
}
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
Box::new(self.items.clone().shrink().map(|items| PartialWithErrors {
items,
_marker: PhantomData,
}))
}
}
impl Arbitrary for PartialOp {
fn arbitrary(_g: &mut Gen) -> Self {
unimplemented!();
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
match *self {
PartialOp::Limited(n) => {
Box::new(n.shrink().filter(|k| k != &0).map(PartialOp::Limited))
}
_ => empty_shrinker(),
}
}
}