use std::io;
use std::marker::PhantomData;
use std::ops::Deref;
use quickcheck::{empty_shrinker, Arbitrary, Gen};
use crate::PartialOp;
#[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<G: Gen>(&mut self, g: &mut G) -> 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<G: Gen>(&mut self, g: &mut G) -> Option<io::ErrorKind> {
if g.gen_weighted_bool(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<G: Gen>(&mut self, _g: &mut G) -> Option<io::ErrorKind> {
None
}
}
impl<GE> Arbitrary for PartialWithErrors<GE>
where
GE: GenError + 'static,
{
fn arbitrary<G: Gen>(g: &mut G) -> 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 => PartialOp::Limited(g.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: Gen>(_g: &mut G) -> 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(),
}
}
}