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

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

impl<T: Domain> GenericRange<T> {
    /// Results in two ranges if the inputs are disjoint or touching.
    /// Results in two ranges (the "left" and "right" disjoint parts) if the inputs are overlapping or contain one another.
    /// Results in a single range (the disjoint part) if the inputs start or end on the same value.
    /// Returns empty if the inputs are equal.
    ///
    /// # Examples
    /// Disjoint ranges.
    /// ```
    /// use ranges::{GenericRange, OperationResult};
    ///
    /// let a = GenericRange::new_less_than(5);
    /// let b = GenericRange::new_at_least(10);
    ///
    /// assert_eq!(a ^ b, OperationResult::Double(a, b));
    /// ```
    /// Ranges start with the same element.
    /// ```
    /// use ranges::{GenericRange, OperationResult};
    ///
    /// let a = GenericRange::from(0..10);
    /// let b = 0..=8;
    ///
    /// assert_eq!(a ^ b, OperationResult::Single(GenericRange::new_open(8, 10)));
    /// ```
    /// Equal ranges.
    /// ```
    /// use ranges::{GenericRange, OperationResult};
    ///
    /// let a = GenericRange::from(5..=10);
    /// let b = a; // this works because Copy is implemented for i32.
    ///
    /// assert_eq!(a ^ b, OperationResult::Empty);
    /// ```
    pub fn symmetric_difference(self, other: Self) -> OperationResult<T> {
        match self.arrangement(&other) {
            Arrangement::Disjoint { self_less } | Arrangement::Touching { self_less } => {
                let (less, greater) = if self_less { (self, other) } else { (other, self) };
                OperationResult::Double(less, greater)
            }
            Arrangement::Overlapping { self_less, .. } => {
                let (less, greater) = if self_less { (self, other) } else { (other, self) };
                OperationResult::Double(
                    Self {
                        start: less.start,
                        end: Self::invert_border(greater.start),
                    },
                    Self {
                        start: Self::invert_border(less.end),
                        end: greater.end,
                    },
                )
            }
            Arrangement::Containing { self_shorter } => {
                let (short, long) = if self_shorter { (self, other) } else { (other, self) };

                OperationResult::Double(
                    Self {
                        start: long.start,
                        end: Self::invert_border(short.start),
                    },
                    Self {
                        start: Self::invert_border(short.end),
                        end: long.end,
                    },
                )
            }
            Arrangement::Starting { self_shorter, .. } => {
                let (short, long) = if self_shorter { (self, other) } else { (other, self) };

                OperationResult::Single(Self {
                    start: Self::invert_border(short.end),
                    end: long.end,
                })
            }

            Arrangement::Ending { self_shorter, .. } => {
                let (short, long) = if self_shorter { (self, other) } else { (other, self) };

                OperationResult::Single(Self {
                    start: long.start,
                    end: Self::invert_border(short.start),
                })
            }
            Arrangement::Equal => OperationResult::Empty,
            Arrangement::Empty { self_empty: Some(true) } => {
                // ∅ Δ B = (∅ \ B) ∪ (B \ ∅)
                // ∅ Δ B = ∅ ∪ B = B
                OperationResult::Single(other)
            }
            Arrangement::Empty {
                self_empty: Some(false),
            } => {
                // A Δ ∅ = (A \ ∅) ∪ (∅ \ A)
                // A Δ ∅ = B ∪ ∅ = A
                OperationResult::Single(self)
            }
            Arrangement::Empty { self_empty: None } => {
                // A Δ B = (A \ B) ∪ (B \ A)
                // ∅ Δ ∅ = (∅ \ ∅) ∪ (∅ \ ∅) = ∅ ∪ ∅ = ∅
                OperationResult::Empty
            }
        }
    }
}

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

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

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

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

        assert_eq!(a.symmetric_difference(b), OperationResult::Double(a, b));
        assert_eq!(b.symmetric_difference(a), OperationResult::Double(a, b));

        assert_eq!(a ^ b, OperationResult::Double(a, b));
        assert_eq!(b ^ a, OperationResult::Double(a, b));
    }

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

        assert_eq!(a.symmetric_difference(b), OperationResult::Double(a, b));
        assert_eq!(b.symmetric_difference(a), OperationResult::Double(a, b));

        assert_eq!(a ^ b, OperationResult::Double(a, b));
        assert_eq!(b ^ a, OperationResult::Double(a, b));
    }

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

        assert_eq!(
            a.symmetric_difference(b),
            OperationResult::Double(GenericRange::from(0..5), GenericRange::from(10..=15))
        );
        assert_eq!(
            b.symmetric_difference(a),
            OperationResult::Double(GenericRange::from(0..5), GenericRange::from(10..=15))
        );

        assert_eq!(
            a ^ b,
            OperationResult::Double(GenericRange::from(0..5), GenericRange::from(10..=15))
        );
        assert_eq!(
            b ^ a,
            OperationResult::Double(GenericRange::from(0..5), GenericRange::from(10..=15))
        );
    }

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

        assert_eq!(
            a.symmetric_difference(b),
            OperationResult::Double(GenericRange::from(0..5), GenericRange::new_open(8, 10))
        );
        assert_eq!(
            b.symmetric_difference(a),
            OperationResult::Double(GenericRange::from(0..5), GenericRange::new_open(8, 10))
        );

        assert_eq!(
            a ^ b,
            OperationResult::Double(GenericRange::from(0..5), GenericRange::new_open(8, 10))
        );
        assert_eq!(
            b ^ a,
            OperationResult::Double(GenericRange::from(0..5), GenericRange::new_open(8, 10))
        );
    }

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

        assert_eq!(
            a.symmetric_difference(b),
            OperationResult::Single(GenericRange::new_open(8, 10))
        );
        assert_eq!(
            b.symmetric_difference(a),
            OperationResult::Single(GenericRange::new_open(8, 10))
        );

        assert_eq!(a ^ b, OperationResult::Single(GenericRange::new_open(8, 10)));
        assert_eq!(b ^ a, OperationResult::Single(GenericRange::new_open(8, 10)));
    }

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

        assert_eq!(
            a.symmetric_difference(b),
            OperationResult::Single(GenericRange::from(3..5))
        );
        assert_eq!(
            b.symmetric_difference(a),
            OperationResult::Single(GenericRange::from(3..5))
        );

        assert_eq!(a ^ b, OperationResult::Single(GenericRange::from(3..5)));
        assert_eq!(b ^ a, OperationResult::Single(GenericRange::from(3..5)));
    }

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

        assert_eq!(a.symmetric_difference(b), OperationResult::Empty);
        assert_eq!(b.symmetric_difference(a), OperationResult::Empty);

        assert_eq!(a ^ b, OperationResult::Empty);
        assert_eq!(b ^ a, OperationResult::Empty);
    }
}