#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum Bound<T> {
Excluded(T),
Included(T),
}
impl<T> Bound<T> {
pub fn map<U, F>(self, f: F) -> Bound<U>
where
F: FnOnce(T) -> U,
{
match self {
Self::Excluded(t) => Bound::Excluded(f(t)),
Self::Included(t) => Bound::Included(f(t)),
}
}
pub fn flipped(self) -> Bound<T> {
match self {
Self::Excluded(t) => Self::Included(t),
Self::Included(t) => Self::Excluded(t),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct LowerBound<T>(pub(crate) Bound<T>);
impl<T> From<Bound<T>> for LowerBound<T> {
fn from(b: Bound<T>) -> Self {
Self(b)
}
}
impl<T: PartialOrd> PartialOrd for LowerBound<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (&self.0, &other.0) {
(Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => {
a.partial_cmp(&b)
}
(Bound::Included(a), Bound::Excluded(b)) => {
if a == b {
Some(std::cmp::Ordering::Less)
} else {
a.partial_cmp(&b)
}
}
(Bound::Excluded(a), Bound::Included(b)) => {
if a == b {
Some(std::cmp::Ordering::Greater)
} else {
a.partial_cmp(&b)
}
}
}
}
}
impl<T: Ord> Ord for LowerBound<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
impl<T> LowerBound<T> {
pub fn excluded(t: T) -> Self {
Self(Bound::Excluded(t))
}
pub fn included(t: T) -> Self {
Self(Bound::Included(t))
}
pub fn to_bound(self) -> Bound<T>
where
T: Copy,
{
self.0
}
pub fn map<U, F>(self, f: F) -> LowerBound<U>
where
F: FnOnce(T) -> U,
{
LowerBound(self.0.map(f))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct UpperBound<T>(pub(crate) Bound<T>);
impl<T> From<Bound<T>> for UpperBound<T> {
fn from(b: Bound<T>) -> Self {
Self(b)
}
}
impl<T: PartialOrd> PartialOrd for UpperBound<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (&self.0, &other.0) {
(Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => {
a.partial_cmp(&b)
}
(Bound::Included(a), Bound::Excluded(b)) => {
if a == b {
Some(std::cmp::Ordering::Greater)
} else {
a.partial_cmp(&b)
}
}
(Bound::Excluded(a), Bound::Included(b)) => {
if a == b {
Some(std::cmp::Ordering::Less)
} else {
a.partial_cmp(&b)
}
}
}
}
}
impl<T: Ord> Ord for UpperBound<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
impl<T> UpperBound<T> {
pub fn excluded(t: T) -> Self {
Self(Bound::Excluded(t))
}
pub fn included(t: T) -> Self {
Self(Bound::Included(t))
}
pub fn to_bound(self) -> Bound<T>
where
T: Copy,
{
self.0
}
pub fn map<U, F>(self, f: F) -> UpperBound<U>
where
F: FnOnce(T) -> U,
{
UpperBound(self.0.map(f))
}
}