ranges 0.3.3

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::BitOr;

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

impl<T: Domain> GenericRange<T> {
    /// Results in either a single or, if the inputs are disjoint, two ranges.
    ///
    /// # Examples
    /// Disjoint ranges.
    /// ```
    /// use ranges::{GenericRange, OperationResult};
    ///
    /// let range = GenericRange::new_less_than(5);
    /// let range2 = GenericRange::new_at_least(10);
    ///
    /// assert_eq!(range | range2, OperationResult::Double(range, range2));
    /// ```
    /// Overlapping ranges.
    /// ```
    /// use ranges::{GenericRange, OperationResult};
    ///
    /// let range = GenericRange::from(0..10);
    /// let range2 = 5..=15;
    ///
    /// assert_eq!(range | range2, OperationResult::Single((0..=15).into()));
    /// ```
    pub fn union(self, other: Self) -> OperationResult<T> {
        // we can directly create `Self` in all arms because the required `(start <= end)`
        // assertion is already proven by correctly returning `first` and `second` in self.arrangement()
        match self.arrangement(&other) {
            Arrangement::Disjoint { self_less: true } => OperationResult::Double(self, other),
            Arrangement::Disjoint { self_less: false } => OperationResult::Double(other, self),
            Arrangement::Touching { self_less: true } | Arrangement::Overlapping { self_less: true, .. } => {
                OperationResult::Single(Self {
                    start: self.start,
                    end: other.end,
                })
            }
            Arrangement::Touching { self_less: false } | Arrangement::Overlapping { self_less: false, .. } => {
                OperationResult::Single(Self {
                    start: other.start,
                    end: self.end,
                })
            }
            Arrangement::Containing { self_shorter: false }
            | Arrangement::Starting {
                self_shorter: false, ..
            }
            | Arrangement::Ending {
                self_shorter: false, ..
            }
            | Arrangement::Equal
            | Arrangement::Empty {
                self_empty: Some(false),
            } => OperationResult::Single(self),
            Arrangement::Containing { self_shorter: true }
            | Arrangement::Starting { self_shorter: true, .. }
            | Arrangement::Ending { self_shorter: true, .. }
            | Arrangement::Empty { self_empty: Some(true) } => OperationResult::Single(other),
            Arrangement::Empty { self_empty: None } => OperationResult::Empty,
        }
    }
}

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

    #[must_use]
    fn bitor(self, rhs: I) -> Self::Output {
        self.union(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.union(range2), OperationResult::Double(range, range2));
        assert_eq!(range2.union(range), OperationResult::Double(range, range2));

        assert_eq!(range | range2, OperationResult::Double(range, range2));
        assert_eq!(range2 | range, OperationResult::Double(range, range2));
    }

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

        assert_eq!(range.union(range2), OperationResult::Single(GenericRange::from(0..=20)));
        assert_eq!(range2.union(range), OperationResult::Single(GenericRange::from(0..=20)));

        assert_eq!(range | range2, OperationResult::Single(GenericRange::from(0..=20)));
        assert_eq!(range2 | range, OperationResult::Single(GenericRange::from(0..=20)));
    }

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

        assert_eq!(range.union(range2), OperationResult::Single(GenericRange::from(0..=15)));
        assert_eq!(range2.union(range), OperationResult::Single(GenericRange::from(0..=15)));

        assert_eq!(range | range2, OperationResult::Single(GenericRange::from(0..=15)));
        assert_eq!(range2 | range, OperationResult::Single(GenericRange::from(0..=15)));
    }

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

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

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

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

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

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

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

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

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

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

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

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