use crate::parts::*;
use crate::shorthands::aliases::*;
use core::cmp::Ordering;
use core::ops::{Bound, RangeBounds};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Edge<T> {
pub side: Side,
pub bound: Bound<T>,
}
impl<T> Edge<T> {
pub fn new(side: Side, bound: Bound<T>) -> Self {
Self { side, bound }
}
pub fn is_unbounded(&self) -> bool {
matches!(self.bound.as_ref(), Ub)
}
pub fn is_included(&self) -> bool {
matches!(self.bound.as_ref(), In(_))
}
pub fn is_excluded(&self) -> bool {
matches!(self.bound.as_ref(), Ex(_))
}
pub fn side(self) -> Side {
self.side
}
pub fn bound(self) -> Bound<T> {
self.bound
}
pub fn pos(self) -> Option<T> {
bound(self.bound).pos()
}
pub fn as_ref(&self) -> Edge<&T> {
Edge::new(self.side, self.bound.as_ref())
}
pub fn with_bound(self, value: Bound<T>) -> Self {
Self::new(self.side, value)
}
pub fn with_included(self, included: bool) -> Self {
Self::new(self.side, bound(self.bound).with_included(included))
}
pub fn with_pos(self, value: T) -> Self {
Self::new(self.side, bound(self.bound).with_pos(value))
}
pub fn map<F, U>(self, f: F) -> Edge<U>
where
F: FnMut(T) -> U,
{
Edge::new(self.side, self.bound.map(f))
}
pub fn try_map<F, U>(self, f: F) -> Option<Edge<U>>
where
F: FnMut(T) -> Option<U>,
{
Some(Edge::new(self.side, bound(self.bound).try_map(f)?))
}
}
impl<T> Edge<&T> {
pub fn cloned(&self) -> Edge<T>
where
T: Clone,
{
Edge::new(self.side, self.bound.cloned())
}
}
impl<T> Edge<T> {
pub(crate) fn is_contained<R>(&self, range: &R) -> bool
where
T: PartialOrd,
R: ?Sized + RangeBounds<T>,
{
let rs = Edge::new(Side::S, range.start_bound());
let re = Edge::new(Side::E, range.end_bound());
rs <= self.as_ref() && self.as_ref() <= re
}
}
impl<T> Edge<T> {
fn parts(&self) -> (i8, Option<&T>, Option<i8>) {
(self.part_inf(), self.part_pos(), self.part_bound_variant())
}
fn part_inf(&self) -> i8 {
match (self.is_unbounded(), self.side) {
(false, _) => 0,
(true, Side::S) => -1,
(true, Side::E) => 1,
}
}
fn part_pos(&self) -> Option<&T> {
self.as_ref().pos()
}
fn part_bound_variant(&self) -> Option<i8> {
match (&self.bound, self.side) {
(Ub, _) => None,
(In(_), _) => Some(0),
(Ex(_), Side::S) => Some(1),
(Ex(_), Side::E) => Some(-1),
}
}
}
impl<T> Ord for Edge<T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.parts().cmp(&other.parts())
}
}
impl<T> PartialOrd for Edge<T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.parts().partial_cmp(&other.parts())
}
}