use crate::bound::Bound;
use crate::raw_interval::RawInterval;
#[cfg(feature="serde")] use serde::Deserialize;
#[cfg(feature="serde")] use serde::Serialize;
use few::Few;
use std::cmp::Ordering;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature="serde", derive(Deserialize, Serialize))]
pub enum Tine<T> {
Lower(Bound<T>),
Point(Bound<T>),
Upper(Bound<T>),
}
impl<T> Tine<T> where T: PartialOrd + Ord + Clone {
pub fn from_raw_interval(interval: RawInterval<T>) -> Few<Self> {
use RawInterval::*;
use Bound::*;
use Tine::{ Lower, Upper };
match interval {
Empty => Few::Zero,
Point(p) => Few::One(Self::Point(Include(p))),
Open(l, r) => Few::Two(Lower(Exclude(l)), Upper(Exclude(r))),
LeftOpen(l, r) => Few::Two(Lower(Exclude(l)), Upper(Include(r))),
RightOpen(l, r) => Few::Two(Lower(Include(l)), Upper(Exclude(r))),
Closed(l, r) => Few::Two(Lower(Include(l)), Upper(Include(r))),
UpTo(r) => Few::Two(Lower(Infinite), Upper(Exclude(r))),
UpFrom(l) => Few::Two(Lower(Exclude(l)), Upper(Infinite)),
To(r) => Few::Two(Lower(Infinite), Upper(Include(r))),
From(l) => Few::Two(Lower(Include(l)), Upper(Infinite)),
Full => Few::Two(Lower(Infinite), Upper(Infinite)),
}
}
pub fn is_lower_bound(&self) -> bool {
use Bound::*;
use Tine::*;
matches!(self,
Lower(_) |
Point(Exclude(_)) )
}
pub fn is_upper_bound(&self) -> bool {
use Bound::*;
use Tine::*;
matches!(self,
Upper(_) |
Point(Exclude(_)) )
}
pub fn is_point_include(&self) -> bool {
use Bound::*;
use Tine::*;
matches!(self, Point(Include(_)))
}
pub fn is_point_exclude(&self) -> bool {
use Bound::*;
use Tine::*;
matches!(self, Point(Exclude(_)))
}
pub fn as_ref(&self) -> Option<&T> {
use Tine::*;
match self {
Lower(x) |
Point(x) |
Upper(x) => x.as_ref(),
}
}
pub fn into_inner(self) -> Bound<T> {
use Tine::*;
match self {
Lower(x) |
Point(x) |
Upper(x) => x,
}
}
pub fn union(self, other: &Self) -> Option<Self> {
use Bound::*;
use Tine::*;
debug_assert!(self.as_ref() == other.as_ref(),
"cannot union unequal tines");
match (self, other) {
(Lower(Include(l)), &Lower(Exclude(_))) => Some(Lower(Include(l))),
(Lower(Exclude(l)), &Lower(Include(_))) => Some(Lower(Include(l))),
(Lower(lb), &Lower(_)) => Some(Lower(lb)),
(Lower(Include(l)), &Point(Include(_))) => Some(Lower(Include(l))),
(Lower(Include(_)), &Point(Exclude(_))) => None,
(Lower(Exclude(l)), &Point(Include(_))) => Some(Lower(Include(l))),
(Lower(Exclude(l)), &Point(Exclude(_))) => Some(Point(Exclude(l))),
(Lower(Include(_)), &Upper(Include(_))) => None,
(Lower(Include(_)), &Upper(Exclude(_))) => None,
(Lower(Exclude(_)), &Upper(Include(_))) => None,
(Lower(Exclude(l)), &Upper(Exclude(_))) => Some(Point(Exclude(l))),
(Point(Include(l)), &Lower(_)) => Some(Lower(Include(l))),
(Point(Include(l)), &Point(Include(_))) => Some(Point(Include(l))),
(Point(Include(l)), &Upper(_)) => Some(Upper(Include(l))),
(Point(Include(_)), _) => None,
(Point(Exclude(l)), &Lower(Exclude(_))) => Some(Point(Exclude(l))),
(Point(Exclude(l)), &Point(Exclude(_))) => Some(Point(Exclude(l))),
(Point(Exclude(l)), &Upper(Exclude(_))) => Some(Point(Exclude(l))),
(Point(Exclude(_)), _) => None,
(Upper(Include(_)), &Lower(Include(_))) => None,
(Upper(Include(_)), &Lower(Exclude(_))) => None,
(Upper(Exclude(_)), &Lower(Include(_))) => None,
(Upper(Exclude(l)), &Lower(Exclude(_))) => Some(Point(Exclude(l))),
(Upper(Include(l)), &Point(Include(_))) => Some(Upper(Include(l))),
(Upper(Include(_)), &Point(Exclude(_))) => None,
(Upper(Exclude(l)), &Point(Include(_))) => Some(Upper(Include(l))),
(Upper(Exclude(l)), &Point(Exclude(_))) => Some(Point(Exclude(l))),
(Upper(Include(l)), &Upper(Exclude(_))) => Some(Upper(Include(l))),
(Upper(Exclude(l)), &Upper(Include(_))) => Some(Upper(Include(l))),
(Upper(lb), &Upper(_)) => Some(Upper(lb)),
_ => unreachable!("invalid tine union"),
}
}
pub fn intersect(self, other: &Self) -> Option<Self> {
use Bound::*;
use Tine::*;
debug_assert!(self.as_ref() == other.as_ref(),
"cannot intersect unequal tines");
match (self, other) {
(Lower(Include(l)), &Lower(Exclude(_))) => Some(Lower(Exclude(l))),
(Lower(Exclude(l)), &Lower(Include(_))) => Some(Lower(Exclude(l))),
(Lower(lb), &Lower(_)) => Some(Lower(lb)),
(Lower(Include(l)), &Point(Include(_))) => Some(Point(Include(l))),
(Lower(Exclude(l)), &Point(Exclude(_))) => Some(Lower(Exclude(l))),
(Lower(_), &Point(_)) => None,
(Lower(Include(l)), &Upper(Include(_))) => Some(Point(Include(l))),
(Lower(_), &Upper(_)) => None,
(Point(Include(l)), &Lower(Include(_))) => Some(Point(Include(l))),
(Point(Include(l)), &Point(Include(_))) => Some(Point(Include(l))),
(Point(Include(l)), &Upper(Include(_))) => Some(Point(Include(l))),
(Point(Include(_)), _) => None,
(Point(Exclude(l)), &Lower(_)) => Some(Lower(Exclude(l))),
(Point(Exclude(_)), &Point(Include(_))) => None,
(Point(Exclude(l)), &Point(Exclude(_))) => Some(Point(Exclude(l))),
(Point(Exclude(l)), &Upper(_)) => Some(Upper(Exclude(l))),
(Upper(Include(l)), &Lower(Include(_))) => Some(Point(Include(l))),
(Upper(_), &Lower(_)) => None,
(Upper(Include(l)), &Point(Include(_))) => Some(Point(Include(l))),
(Upper(Exclude(l)), &Point(Exclude(_))) => Some(Upper(Exclude(l))),
(Upper(_), &Point(_)) => None,
(Upper(Include(l)), &Upper(Exclude(_))) => Some(Upper(Exclude(l))),
(Upper(Exclude(l)), &Upper(Include(_))) => Some(Upper(Exclude(l))),
(Upper(lb), &Upper(_)) => Some(Upper(lb)),
_ => unreachable!("invalid tine intersect"),
}
}
pub fn minus(self, other: &Self) -> Option<Self> {
use Bound::*;
use Tine::*;
debug_assert!(self.as_ref() == other.as_ref(),
"cannot intersect unequal tines");
match (self, other) {
(Lower(Include(l)), &Lower(Exclude(_))) => Some(Point(Include(l))),
(Lower(_), &Lower(_)) => None,
(Lower(Include(l)), &Point(Include(_))) => Some(Lower(Exclude(l))),
(Lower(_), &Point(_)) => None,
(Lower(Include(l)), &Upper(Include(_))) => Some(Lower(Exclude(l))),
(Lower(Include(l)), &Upper(Exclude(_))) => Some(Lower(Include(l))),
(Lower(Exclude(l)), &Upper(Include(_))) => Some(Lower(Exclude(l))),
(Lower(Exclude(l)), &Upper(Exclude(_))) => Some(Lower(Exclude(l))),
(Point(Include(_)), &Lower(Include(_))) => None,
(Point(Include(_)), &Point(Include(_))) => None,
(Point(Include(_)), &Upper(Include(_))) => None,
(Point(Include(l)), _) => Some(Point(Include(l))),
(Point(Exclude(l)), &Lower(_)) => Some(Lower(Exclude(l))),
(Point(Exclude(l)), &Point(Include(_))) => Some(Point(Exclude(l))),
(Point(Exclude(_)), &Point(Exclude(_))) => None,
(Point(Exclude(l)), &Upper(_)) => Some(Upper(Exclude(l))),
(Upper(Include(l)), &Lower(Include(_))) => Some(Upper(Exclude(l))),
(Upper(Include(l)), &Lower(Exclude(_))) => Some(Upper(Include(l))),
(Upper(Exclude(l)), &Lower(Include(_))) => Some(Upper(Exclude(l))),
(Upper(Exclude(l)), &Lower(Exclude(_))) => Some(Upper(Exclude(l))),
(Upper(Include(l)), &Point(Include(_))) => Some(Upper(Exclude(l))),
(Upper(_), &Point(_)) => None,
(Upper(Include(l)), &Upper(Exclude(_))) => Some(Point(Include(l))),
(Upper(_), &Upper(_)) => None,
_ => unreachable!("invalid tine intersect"),
}
}
#[must_use]
pub fn invert(self) -> Self {
use Bound::*;
use Tine::*;
match self {
Lower(Include(p)) => Upper(Exclude(p)),
Lower(Exclude(p)) => Upper(Include(p)),
Point(Include(p)) => Point(Exclude(p)),
Point(Exclude(p)) => Point(Include(p)),
Upper(Include(p)) => Lower(Exclude(p)),
Upper(Exclude(p)) => Lower(Include(p)),
_ => panic!("cannot invert infinite Tine"),
}
}
}
impl<T> PartialOrd for Tine<T> where T: PartialOrd + Ord + Clone {
#[allow(clippy::non_canonical_partial_ord_impl)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if let (Some(l), Some(r)) = (self.as_ref(), other.as_ref()) {
l.partial_cmp(r)
} else {
use Bound::*;
use Tine::*;
use Ordering::*;
match (self, other) {
(&Lower(Infinite), &Lower(Infinite)) |
(&Upper(Infinite), &Upper(Infinite)) => Some(Equal),
(&Lower(Infinite), _) => Some(Less),
(&Upper(Infinite), _) => Some(Greater),
(_, &Upper(Infinite)) => Some(Less),
(_, &Lower(Infinite)) => Some(Greater),
_ => unreachable!("invalid Tine value"),
}
}
}
}
impl<T> Ord for Tine<T> where T: PartialOrd + Ord + Clone {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}