use std::cmp::Ordering;
use std::ops::Bound;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub(crate) enum BoundOrd<T> {
Included(T),
StartExcluded(T),
StartUnbounded,
EndExcluded(T),
EndUnbounded,
}
impl<T> BoundOrd<T> {
pub(crate) fn start(bound: Bound<T>) -> Self {
match bound {
Bound::Included(point) => BoundOrd::Included(point),
Bound::Excluded(point) => BoundOrd::StartExcluded(point),
Bound::Unbounded => BoundOrd::StartUnbounded,
}
}
pub(crate) fn end(bound: Bound<T>) -> Self {
match bound {
Bound::Included(point) => BoundOrd::Included(point),
Bound::Excluded(point) => BoundOrd::EndExcluded(point),
Bound::Unbounded => BoundOrd::EndUnbounded,
}
}
}
impl<T> Ord for BoundOrd<T>
where
T: Ord,
{
#[rustfmt::skip]
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(BoundOrd::Included(start1), BoundOrd::Included(start2)) => start1.cmp(start2),
(BoundOrd::Included(start1), BoundOrd::StartExcluded(start2)) => cmp_with_priority(start1, start2, true),
(BoundOrd::Included(start1), BoundOrd::EndExcluded(start2)) => cmp_with_priority(start1, start2, false),
(BoundOrd::Included(_), BoundOrd::EndUnbounded) => Ordering::Less,
(BoundOrd::Included(_), BoundOrd::StartUnbounded) => Ordering::Greater,
(BoundOrd::StartExcluded(start1), BoundOrd::StartExcluded(start2)) => start1.cmp(start2),
(BoundOrd::StartExcluded(start1), BoundOrd::Included(start2)) => cmp_with_priority(start1, start2, false),
(BoundOrd::StartExcluded(start1), BoundOrd::EndExcluded(start2)) => cmp_with_priority(start1, start2, false),
(BoundOrd::StartExcluded(_), BoundOrd::StartUnbounded) => Ordering::Greater,
(BoundOrd::StartExcluded(_), BoundOrd::EndUnbounded) => Ordering::Less,
(BoundOrd::StartUnbounded, BoundOrd::Included(_)) => Ordering::Less,
(BoundOrd::StartUnbounded, BoundOrd::StartExcluded(_)) => Ordering::Less,
(BoundOrd::StartUnbounded, BoundOrd::EndExcluded(_)) => Ordering::Less,
(BoundOrd::StartUnbounded, BoundOrd::StartUnbounded) => Ordering::Equal,
(BoundOrd::StartUnbounded, BoundOrd::EndUnbounded) => Ordering::Less,
(BoundOrd::EndExcluded(start1), BoundOrd::EndExcluded(start2)) => start1.cmp(start2),
(BoundOrd::EndExcluded(start1), BoundOrd::Included(start2)) => cmp_with_priority(start1, start2, true),
(BoundOrd::EndExcluded(start1), BoundOrd::StartExcluded(start2)) => cmp_with_priority(start1, start2, true),
(BoundOrd::EndExcluded(_), BoundOrd::StartUnbounded) => Ordering::Greater,
(BoundOrd::EndExcluded(_), BoundOrd::EndUnbounded) => Ordering::Less,
(BoundOrd::EndUnbounded, BoundOrd::Included(_)) => Ordering::Greater,
(BoundOrd::EndUnbounded, BoundOrd::StartExcluded(_)) => Ordering::Greater,
(BoundOrd::EndUnbounded, BoundOrd::EndExcluded(_)) => Ordering::Greater,
(BoundOrd::EndUnbounded, BoundOrd::EndUnbounded) => Ordering::Equal,
(BoundOrd::EndUnbounded, BoundOrd::StartUnbounded) => Ordering::Greater,
}
}
}
impl<T> PartialOrd for BoundOrd<T>
where
T: Ord,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T> PartialEq for BoundOrd<T>
where
T: Ord,
{
fn eq(&self, other: &Self) -> bool {
self.cmp(other).is_eq()
}
}
impl<T> Eq for BoundOrd<T> where T: Ord {}
fn cmp_with_priority<T>(left: &T, right: &T, priority: bool) -> Ordering
where
T: Ord,
{
let result = left.cmp(right);
match result {
Ordering::Equal => match priority {
false => Ordering::Greater,
true => Ordering::Less,
},
x => x,
}
}
impl<T> From<BoundOrd<T>> for Bound<T> {
fn from(start_bound: BoundOrd<T>) -> Bound<T> {
match start_bound {
BoundOrd::Included(point) => Bound::Included(point),
BoundOrd::StartExcluded(point) => Bound::Excluded(point),
BoundOrd::StartUnbounded => Bound::Unbounded,
BoundOrd::EndExcluded(point) => Bound::Excluded(point),
BoundOrd::EndUnbounded => Bound::Unbounded,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mass_start_bound_partial_ord_test() {
assert!(BoundOrd::Included(2) == BoundOrd::Included(2));
assert!(BoundOrd::Included(2) <= BoundOrd::Included(2));
assert!(BoundOrd::Included(2) >= BoundOrd::Included(2));
assert!(BoundOrd::Included(0) < BoundOrd::Included(2));
assert!(BoundOrd::Included(2) > BoundOrd::Included(0));
assert!(BoundOrd::Included(2) < BoundOrd::StartExcluded(2));
assert!(BoundOrd::Included(0) < BoundOrd::StartExcluded(2));
assert!(BoundOrd::Included(2) > BoundOrd::StartExcluded(0));
assert!(BoundOrd::Included(2) > BoundOrd::StartUnbounded);
assert!(BoundOrd::Included(2) > BoundOrd::EndExcluded(2));
assert!(BoundOrd::Included(0) < BoundOrd::EndExcluded(2));
assert!(BoundOrd::Included(2) > BoundOrd::EndExcluded(0));
assert!(BoundOrd::Included(2) < BoundOrd::EndUnbounded);
assert!(BoundOrd::StartExcluded(2) == BoundOrd::StartExcluded(2));
assert!(BoundOrd::StartExcluded(2) <= BoundOrd::StartExcluded(2));
assert!(BoundOrd::StartExcluded(2) >= BoundOrd::StartExcluded(2));
assert!(BoundOrd::StartExcluded(0) < BoundOrd::StartExcluded(2));
assert!(BoundOrd::StartExcluded(2) > BoundOrd::StartExcluded(0));
assert!(BoundOrd::StartExcluded(2) > BoundOrd::StartUnbounded);
assert!(BoundOrd::StartExcluded(2) > BoundOrd::EndExcluded(2));
assert!(BoundOrd::StartExcluded(2) > BoundOrd::EndExcluded(0));
assert!(BoundOrd::StartExcluded(0) < BoundOrd::EndExcluded(2));
assert!(BoundOrd::StartExcluded(2) < BoundOrd::EndUnbounded);
assert!(BoundOrd::StartUnbounded::<i8> == BoundOrd::StartUnbounded);
assert!(BoundOrd::StartUnbounded::<i8> <= BoundOrd::StartUnbounded);
assert!(BoundOrd::StartUnbounded::<i8> >= BoundOrd::StartUnbounded);
assert!(BoundOrd::StartUnbounded < BoundOrd::EndExcluded(2));
assert!(BoundOrd::StartUnbounded::<i8> < BoundOrd::EndUnbounded);
assert!(BoundOrd::EndExcluded(2) == BoundOrd::EndExcluded(2));
assert!(BoundOrd::EndExcluded(2) <= BoundOrd::EndExcluded(2));
assert!(BoundOrd::EndExcluded(2) >= BoundOrd::EndExcluded(2));
assert!(BoundOrd::EndExcluded(0) < BoundOrd::EndExcluded(2));
assert!(BoundOrd::EndExcluded(2) > BoundOrd::EndExcluded(0));
assert!(BoundOrd::EndUnbounded::<i8> == BoundOrd::EndUnbounded);
assert!(BoundOrd::EndUnbounded::<i8> <= BoundOrd::EndUnbounded);
assert!(BoundOrd::EndUnbounded::<i8> >= BoundOrd::EndUnbounded);
}
}