use core::ops::BitOr;
use crate::{Arrangement, Domain, GenericRange, OperationResult};
impl<T: Domain> GenericRange<T> {
pub fn union(self, other: Self) -> OperationResult<T> {
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,
}
}
}
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));
}
}