#![forbid(unsafe_code)]
use core::fmt::Debug;
use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
use std::cmp::Ordering;
use std::ops::RangeBounds;
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum AnyRange<T: Clone + PartialOrd + PartialEq> {
Range(Range<T>),
RangeFrom(RangeFrom<T>),
RangeFull(RangeFull),
RangeInclusive(RangeInclusive<T>),
RangeTo(RangeTo<T>),
RangeToInclusive(RangeToInclusive<T>),
}
impl<T: Clone + PartialOrd + PartialEq> AnyRange<T> {
#[must_use]
pub fn bounds(&self) -> (Bound<T>, Bound<T>) {
(self.start_bound().cloned(), self.end_bound().cloned())
}
pub fn contains(&self, value: &T) -> bool {
RangeBounds::contains(self, value)
}
pub fn start_bound(&self) -> Bound<&T> {
RangeBounds::start_bound(self)
}
pub fn end_bound(&self) -> Bound<&T> {
RangeBounds::end_bound(self)
}
fn order(&self) -> u8 {
match self {
Self::Range(_) => 0,
Self::RangeFrom(_) => 1,
Self::RangeFull(_) => 2,
Self::RangeInclusive(_) => 3,
Self::RangeTo(_) => 4,
Self::RangeToInclusive(_) => 5,
}
}
}
impl<T: Clone + PartialOrd + PartialEq> RangeBounds<T> for AnyRange<T> {
fn start_bound(&self) -> Bound<&T> {
match self {
Self::Range(r) => r.start_bound(),
Self::RangeFrom(r) => r.start_bound(),
Self::RangeFull(r) => r.start_bound(),
Self::RangeInclusive(r) => r.start_bound(),
Self::RangeTo(r) => r.start_bound(),
Self::RangeToInclusive(r) => r.start_bound(),
}
}
fn end_bound(&self) -> Bound<&T> {
match self {
Self::Range(r) => r.end_bound(),
Self::RangeFrom(r) => r.end_bound(),
Self::RangeFull(r) => r.end_bound(),
Self::RangeInclusive(r) => r.end_bound(),
Self::RangeTo(r) => r.end_bound(),
Self::RangeToInclusive(r) => r.end_bound(),
}
}
}
impl<T: Clone + PartialOrd + PartialEq> From<Range<T>> for AnyRange<T> {
fn from(r: Range<T>) -> Self {
Self::Range(r)
}
}
impl<T: Clone + PartialOrd + PartialEq> From<RangeFrom<T>> for AnyRange<T> {
fn from(r: RangeFrom<T>) -> Self {
Self::RangeFrom(r)
}
}
impl<T: Clone + PartialOrd + PartialEq> From<RangeFull> for AnyRange<T> {
fn from(r: RangeFull) -> Self {
Self::RangeFull(r)
}
}
impl<T: Clone + PartialOrd + PartialEq> From<RangeInclusive<T>> for AnyRange<T> {
fn from(r: RangeInclusive<T>) -> Self {
Self::RangeInclusive(r)
}
}
impl<T: Clone + PartialOrd + PartialEq> From<RangeTo<T>> for AnyRange<T> {
fn from(r: RangeTo<T>) -> Self {
Self::RangeTo(r)
}
}
impl<T: Clone + PartialOrd + PartialEq> From<RangeToInclusive<T>> for AnyRange<T> {
fn from(r: RangeToInclusive<T>) -> Self {
Self::RangeToInclusive(r)
}
}
impl<T: Clone + PartialOrd + PartialEq + Debug> Debug for AnyRange<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
match self {
AnyRange::Range(r) => write!(f, "AnyRange({r:?})"),
AnyRange::RangeFrom(r) => write!(f, "AnyRange({r:?})"),
AnyRange::RangeFull(r) => write!(f, "AnyRange({r:?})"),
AnyRange::RangeInclusive(r) => write!(f, "AnyRange({r:?})"),
AnyRange::RangeTo(r) => write!(f, "AnyRange({r:?})"),
AnyRange::RangeToInclusive(r) => write!(f, "AnyRange({r:?})"),
}
}
}
impl<T: Clone + PartialOrd + PartialEq + Debug> PartialOrd for AnyRange<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(AnyRange::Range(a), AnyRange::Range(b)) if a.start == b.start => {
a.end.partial_cmp(&b.end)
}
(AnyRange::Range(a), AnyRange::Range(b)) => a.start.partial_cmp(&b.start),
(AnyRange::RangeFrom(a), AnyRange::RangeFrom(b)) => a.start.partial_cmp(&b.start),
(AnyRange::RangeFull(_), AnyRange::RangeFull(_)) => Some(Ordering::Equal),
(AnyRange::RangeInclusive(a), AnyRange::RangeInclusive(b))
if a.start() == b.start() =>
{
a.end().partial_cmp(b.end())
}
(AnyRange::RangeInclusive(a), AnyRange::RangeInclusive(b)) => {
a.start().partial_cmp(b.start())
}
(AnyRange::RangeTo(a), AnyRange::RangeTo(b)) => a.end.partial_cmp(&b.end),
(AnyRange::RangeToInclusive(a), AnyRange::RangeToInclusive(b)) => {
a.end.partial_cmp(&b.end)
}
(a, b) => a.order().partial_cmp(&b.order()),
}
}
}
impl<T: Clone + PartialOrd + PartialEq + Eq + Debug> Ord for AnyRange<T> {
fn cmp(&self, other: &Self) -> Ordering {
PartialOrd::partial_cmp(self, other).unwrap()
}
}