use core::{cmp::Ordering, ops::Bound};
use arbitrary::{Arbitrary, Result, Unstructured};
use crate::{Domain, GenericRange};
#[allow(clippy::missing_docs_in_private_items)]
enum RangeType {
Unbounded,
SingleBound,
DoubleBound,
}
#[allow(clippy::missing_docs_in_private_items)]
enum SingleBoundType {
LeftInclude,
LeftExclude,
RightInclude,
RightExclude,
}
#[allow(clippy::missing_docs_in_private_items)]
enum DoubleBoundType {
InIn,
InEx,
ExIn,
ExEx,
}
impl<'data, T: Arbitrary<'data> + Domain> Arbitrary<'data> for GenericRange<T> {
#[allow(clippy::min_ident_chars)]
fn arbitrary(u: &mut Unstructured<'data>) -> Result<Self> {
let ty = u.choose(&[RangeType::Unbounded, RangeType::SingleBound, RangeType::DoubleBound])?;
Ok(match *ty {
RangeType::Unbounded => Self::full(),
RangeType::SingleBound => {
let bound = u.choose(&[
SingleBoundType::LeftInclude,
SingleBoundType::LeftExclude,
SingleBoundType::RightInclude,
SingleBoundType::RightExclude,
])?;
let val = u.arbitrary::<T>()?;
match *bound {
SingleBoundType::LeftInclude => Self::new_with_bounds(Bound::Included(val), Bound::Unbounded),
SingleBoundType::LeftExclude => Self::new_with_bounds(Bound::Excluded(val), Bound::Unbounded),
SingleBoundType::RightInclude => Self::new_with_bounds(Bound::Unbounded, Bound::Included(val)),
SingleBoundType::RightExclude => Self::new_with_bounds(Bound::Unbounded, Bound::Excluded(val)),
}
}
RangeType::DoubleBound => {
let bound = u.choose(&[
DoubleBoundType::InIn,
DoubleBoundType::InEx,
DoubleBoundType::ExIn,
DoubleBoundType::ExEx,
])?;
let val1 = u.arbitrary::<T>()?;
let val2 = u.arbitrary::<T>()?;
let (big, small) = match val1.cmp(&val2) {
Ordering::Less => (val2, val1),
Ordering::Equal | Ordering::Greater => (val1, val2),
};
match *bound {
DoubleBoundType::InIn => Self::new_with_bounds(Bound::Included(small), Bound::Included(big)),
DoubleBoundType::InEx => Self::new_with_bounds(Bound::Included(small), Bound::Excluded(big)),
DoubleBoundType::ExIn => Self::new_with_bounds(Bound::Excluded(small), Bound::Included(big)),
DoubleBoundType::ExEx => Self::new_with_bounds(Bound::Excluded(small), Bound::Excluded(big)),
}
}
})
}
}