use core::ops::BitXor;
use crate::{Arrangement, Domain, GenericRange, OperationResult};
impl<T: Domain> GenericRange<T> {
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) } => {
OperationResult::Single(other)
}
Arrangement::Empty {
self_empty: Some(false),
} => {
OperationResult::Single(self)
}
Arrangement::Empty { self_empty: None } => {
OperationResult::Empty
}
}
}
}
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);
}
}