ranges 0.4.0

This crate provides a generic alternative to core/std ranges, set-operations to work with them and a range set that can efficiently store them with the least amount of memory possible.
Documentation
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 => {
                // no unbound
                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)),
                }
            }
        })
    }
}