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::ops::BitAnd;

use crate::{Arrangement, Domain, GenericRange, OperationResult};

impl<T: Domain> GenericRange<T> {
    /// Results in either a single or, if the inputs are disjoint, empty range.
    ///
    /// # Note
    /// The `OperationResult::Double` discriminant can safely be marked `unreachable!()` when
    /// matching the output of this method.
    ///
    /// # Examples
    /// ```
    /// use ranges::{GenericRange, OperationResult};
    ///
    /// let range = GenericRange::new_less_than(5);
    /// let range2 = GenericRange::new_at_least(10);
    ///
    /// assert_eq!(range & range2, OperationResult::Empty);
    /// ```
    /// ```
    /// use ranges::{GenericRange, OperationResult};
    ///
    /// let range = GenericRange::from(0..10);
    /// let range2 = 5..=15;
    ///
    /// assert_eq!(range & range2, OperationResult::Single(GenericRange::from(5..10)));
    /// ```
    pub fn intersect(self, other: Self) -> OperationResult<T> {
        match self.arrangement(&other) {
            Arrangement::Disjoint { .. } | Arrangement::Touching { .. } => OperationResult::Empty,
            Arrangement::Overlapping { self_less, .. } => {
                let (less, greater) = if self_less { (self, other) } else { (other, self) };
                OperationResult::Single(Self {
                    start: greater.start,
                    end: less.end,
                })
            }
            Arrangement::Containing { self_shorter }
            | Arrangement::Starting { self_shorter, .. }
            | Arrangement::Ending { self_shorter, .. } => {
                let short = if self_shorter { self } else { other };

                OperationResult::Single(short)
            }
            Arrangement::Equal => OperationResult::Single(self),
            Arrangement::Empty { .. } => {
                // A ∩ ∅ = ∅
                // ∅ ∩ A = ∅
                OperationResult::Empty
            }
        }
    }
}

/// This calls [`self.intersect(other)`](#method.intersect).
impl<T, I> BitAnd<I> for GenericRange<T>
where
    I: Into<GenericRange<T>>,
    T: Domain,
{
    type Output = OperationResult<T>;

    #[must_use]
    fn bitand(self, rhs: I) -> Self::Output {
        self.intersect(rhs.into())
    }
}

#[cfg(test)]
mod tests {
    use crate::{GenericRange, OperationResult};

    #[test]
    fn disjoint() {
        let range = GenericRange::new_less_than(5);
        let range2 = GenericRange::new_at_least(10);

        assert_eq!(range.intersect(range2), OperationResult::Empty);
        assert_eq!(range2.intersect(range), OperationResult::Empty);

        assert_eq!(range & range2, OperationResult::Empty);
        assert_eq!(range2 & range, OperationResult::Empty);
    }

    #[test]
    fn touching() {
        let range = GenericRange::from(0..10);
        let range2 = GenericRange::from(10..=20);

        assert_eq!(range.intersect(range2), OperationResult::Empty);
        assert_eq!(range2.intersect(range), OperationResult::Empty);

        assert_eq!(range & range2, OperationResult::Empty);
        assert_eq!(range2 & range, OperationResult::Empty);
    }

    #[test]
    fn overlapping() {
        let range = GenericRange::from(0..10);
        let range2 = GenericRange::from(5..=15);

        assert_eq!(
            range.intersect(range2),
            OperationResult::Single(GenericRange::from(5..10))
        );
        assert_eq!(
            range2.intersect(range),
            OperationResult::Single(GenericRange::from(5..10))
        );

        assert_eq!(range & range2, OperationResult::Single(GenericRange::from(5..10)));
        assert_eq!(range2 & range, OperationResult::Single(GenericRange::from(5..10)));
    }

    #[test]
    fn containing() {
        let range = GenericRange::from(0..10);
        let range2 = GenericRange::from(5..=8);

        assert_eq!(range.intersect(range2), OperationResult::Single(range2));
        assert_eq!(range2.intersect(range), OperationResult::Single(range2));

        assert_eq!(range & range2, OperationResult::Single(range2));
        assert_eq!(range2 & range, OperationResult::Single(range2));
    }

    #[test]
    fn starting() {
        let range = GenericRange::from(0..10);
        let range2 = GenericRange::from(0..=8);

        assert_eq!(range.intersect(range2), OperationResult::Single(range2));
        assert_eq!(range2.intersect(range), OperationResult::Single(range2));

        assert_eq!(range & range2, OperationResult::Single(range2));
        assert_eq!(range2 & range, OperationResult::Single(range2));
    }

    #[test]
    fn ending() {
        let range = GenericRange::from(3..=10);
        let range2 = GenericRange::from(5..=10);

        assert_eq!(range.intersect(range2), OperationResult::Single(range2));
        assert_eq!(range2.intersect(range), OperationResult::Single(range2));

        assert_eq!(range & range2, OperationResult::Single(range2));
        assert_eq!(range2 & range, OperationResult::Single(range2));
    }

    #[test]
    fn equal() {
        let range = GenericRange::from(5..=10);
        let range2 = range;

        assert_eq!(range.intersect(range2), OperationResult::Single(range));
        assert_eq!(range2.intersect(range), OperationResult::Single(range));

        assert_eq!(range & range2, OperationResult::Single(range));
        assert_eq!(range2 & range, OperationResult::Single(range));
    }
}