#![allow(clippy::missing_panics_doc, clippy::unused_self)]
use std::{
borrow::Borrow,
fmt,
ops::{self, Add, Bound, Sub},
};
use crate::{ContinuousRange, RangesRelation};
macro_rules! todo {
() => {
panic!("not yet implemented")
};
($($arg:tt)+) => {
panic!("not yet implemented: {}", $crate::format_args!($($arg)+))
};
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, Hash, PartialEq)]
pub enum Range<Idx> {
Continuous(ContinuousRange<Idx>),
Composite(Vec<ContinuousRange<Idx>>),
}
impl<Idx> From<ContinuousRange<Idx>> for Range<Idx> {
fn from(r: ContinuousRange<Idx>) -> Self {
Self::Continuous(r)
}
}
impl<Idx: PartialOrd + Clone> Range<Idx> {
#[must_use]
pub fn empty() -> Self {
Range::Continuous(ContinuousRange::empty())
}
#[must_use]
pub fn single(value: Idx) -> Range<Idx> {
Range::Continuous(ContinuousRange::single(value))
}
#[must_use]
pub fn continuous(start: Idx, end: Idx) -> Self
where
Idx: PartialOrd,
{
Range::Continuous(ContinuousRange::inclusive(start, end))
}
#[must_use]
pub fn continuous_exclusive(start: Idx, end: Idx) -> Self
where
Idx: PartialOrd,
{
Range::Continuous(ContinuousRange::exclusive(start, end))
}
#[must_use]
pub fn continuous_start_exclusive(start: Idx, end: Idx) -> Range<Idx>
where
Idx: PartialOrd,
{
Range::Continuous(ContinuousRange::start_exclusive(start, end))
}
#[must_use]
pub fn continuous_end_exclusive(start: Idx, end: Idx) -> Range<Idx>
where
Idx: PartialOrd,
{
Range::Continuous(ContinuousRange::end_exclusive(start, end))
}
#[must_use]
pub fn from(start: Idx) -> Self {
Self::Continuous(ContinuousRange::from(start))
}
#[must_use]
pub fn from_exclusive(start: Idx) -> Self {
Self::Continuous(ContinuousRange::from_exclusive(start))
}
#[must_use]
pub fn to(end: Idx) -> Self {
Self::Continuous(ContinuousRange::to(end))
}
#[must_use]
pub fn to_exclusive(end: Idx) -> Self {
Self::Continuous(ContinuousRange::to_exclusive(end))
}
#[must_use]
pub fn full() -> Range<Idx> {
Self::Continuous(ContinuousRange::full())
}
#[must_use]
pub fn composite(items: impl IntoIterator<Item = Range<Idx>>) -> Range<Idx>
where
Idx: PartialOrd,
{
let mut iter = items.into_iter();
match iter.size_hint() {
(_, Some(0)) => Self::empty(),
(1, Some(1)) => iter.next().unwrap(),
_ => {
let mut new_items = vec![];
for item in iter {
if item.is_empty() {
continue;
}
if item.is_full() {
return item;
}
match item {
Self::Composite(v) => {
new_items.extend(v);
}
Self::Continuous(r) => new_items.push(r),
}
}
match new_items.len() {
0 => Self::empty(),
1 => Self::Continuous(new_items.into_iter().next().unwrap()),
_ => Self::Composite(new_items),
}
}
}
}
#[must_use]
pub fn range_bounds(&self) -> Option<(Bound<&Idx>, Bound<&Idx>)> {
match self {
Self::Continuous(r) => r.range_bounds(),
Self::Composite(_) => None, }
}
#[must_use]
pub fn contains(&self, value: impl Borrow<Idx>) -> bool
where
Idx: PartialOrd,
{
match self {
Self::Continuous(r) => r.contains(value),
Self::Composite(r) => {
let value = value.borrow();
r.iter().any(|x| x.contains(value))
}
}
}
#[must_use]
pub fn union(&self, other: &Range<Idx>) -> Range<Idx>
where
Idx: PartialOrd,
{
match (self, other) {
(Self::Continuous(ContinuousRange::Empty), r)
| (r, Self::Continuous(ContinuousRange::Empty)) => r.clone(),
(Self::Continuous(ContinuousRange::Full), _)
| (_, Self::Continuous(ContinuousRange::Full)) => Self::full(),
(r1, r2) => Range::composite(vec![r1.clone(), r2.clone()]),
}
}
#[must_use]
pub fn intersection(self, _other: &Range<Idx>) -> Range<Idx> {
todo!()
}
#[must_use]
pub fn difference(self, _other: &Range<Idx>) -> Range<Idx> {
todo!()
}
#[must_use]
pub fn overlaps(self, _other: &Range<Idx>) -> bool {
todo!()
}
#[must_use]
pub fn compare_bounds(&self, _other: &Range<Idx>) -> RangesRelation {
todo!()
}
pub fn simplify_mut(&mut self)
where
Idx: PartialOrd,
{
match self {
Self::Continuous(r) => r.simplify_mut(),
Self::Composite(v) => {
for item in v.iter_mut() {
item.simplify_mut();
}
}
}
}
#[must_use]
pub fn simplify(&self) -> Self
where
Idx: PartialOrd + Clone,
{
let mut clone = (*self).clone();
clone.simplify_mut();
clone
}
#[must_use]
pub fn is_empty(&self) -> bool {
match self {
Self::Continuous(r) => r.is_empty(),
Self::Composite(v) => v.iter().all(ContinuousRange::is_empty),
}
}
#[must_use]
pub fn is_full(&self) -> bool
where
Idx: PartialOrd + Clone,
{
match self.simplify() {
Self::Continuous(r) => r.is_full(),
Self::Composite(v) => v.iter().any(ContinuousRange::is_full),
}
}
}
impl<Idx: PartialOrd + Clone> Add<&Range<Idx>> for Range<Idx> {
type Output = Range<Idx>;
fn add(self, other: &Range<Idx>) -> Range<Idx> {
self.union(other)
}
}
impl<Idx: PartialOrd + Clone> Sub<Range<Idx>> for Range<Idx> {
type Output = Range<Idx>;
fn sub(self, other: Range<Idx>) -> Range<Idx> {
self.difference(&other)
}
}
impl<Idx: PartialOrd + Clone> From<ops::RangeFull> for Range<Idx> {
fn from(_: ops::RangeFull) -> Self {
Self::full()
}
}
impl<Idx: PartialOrd + Clone> From<ops::Range<Idx>> for Range<Idx> {
fn from(r: ops::Range<Idx>) -> Self {
Self::continuous_end_exclusive(r.start, r.end)
}
}
impl<Idx: PartialOrd + Clone> From<ops::RangeInclusive<Idx>> for Range<Idx> {
fn from(r: ops::RangeInclusive<Idx>) -> Self {
let (start, end) = r.into_inner();
Self::continuous(start, end)
}
}
impl<Idx: PartialOrd + Clone> From<ops::RangeFrom<Idx>> for Range<Idx> {
fn from(r: ops::RangeFrom<Idx>) -> Self {
Self::from(r.start)
}
}
impl<Idx: PartialOrd + Clone> From<ops::RangeToInclusive<Idx>> for Range<Idx> {
fn from(r: ops::RangeToInclusive<Idx>) -> Self {
Self::to(r.end)
}
}
impl<Idx: PartialOrd + Clone> From<ops::RangeTo<Idx>> for Range<Idx> {
fn from(r: ops::RangeTo<Idx>) -> Self {
Self::to_exclusive(r.end)
}
}
impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Range::Continuous(r) => {
r.fmt(fmt)?;
}
Range::Composite(r) => {
write!(fmt, "{{")?;
let mut first = true;
for child in r.iter() {
if first {
first = false;
} else {
write!(fmt, "; ")?;
}
fmt::Debug::fmt(child, fmt)?;
}
write!(fmt, "}}")?;
}
}
Ok(())
}
}
impl<Idx> Default for Range<Idx> {
fn default() -> Self {
Self::Continuous(ContinuousRange::Empty)
}
}