use std::mem;
use num_traits::{CheckedAdd, One, Zero};
use crate::{Range, RangeEnd, RangeStart};
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum PartialRange<Idx> {
Empty {
idx: Idx,
},
Exhausted,
From {
inner: std::ops::RangeFrom<Idx>,
},
Inclusive {
start: Idx,
end: Idx,
},
Exclusive {
inner: std::ops::Range<Idx>,
},
}
impl<Idx: Clone + Zero> RangeStart<Idx> for PartialRange<Idx> {
#[inline]
fn start(&self) -> Idx {
match self {
Self::Empty { idx } => idx.clone(),
Self::Exhausted => Idx::zero(),
Self::From { inner } => inner.start.clone(),
Self::Inclusive { start, .. } => start.clone(),
Self::Exclusive { inner } => inner.start.clone(),
}
}
}
impl<Idx: Clone + Ord + Zero> crate::PartialRangeExt<Idx> for PartialRange<Idx> {
#[inline]
fn end_bound(&self) -> Option<RangeEnd<Idx>> {
match self {
Self::Empty { idx } => Some(RangeEnd::Exclusive(idx.clone())),
Self::Exhausted => Some(RangeEnd::Exclusive(Idx::zero())),
Self::From { .. } => None,
Self::Inclusive { end, .. } => Some(RangeEnd::Inclusive(end.clone())),
Self::Exclusive { inner } => Some(RangeEnd::Exclusive(inner.end.clone())),
}
}
}
impl<Idx> Iterator for PartialRange<Idx>
where
Idx: CheckedAdd + Clone + One + PartialOrd,
{
type Item = Idx;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Exhausted => None,
Self::Empty { .. } => {
*self = Self::Exhausted;
None
}
Self::From { inner } => match inner.start.checked_add(&Idx::one()) {
Some(next) if next > inner.start => Some(mem::replace(&mut inner.start, next)),
_ => {
let last = inner.start.clone();
*self = Self::Exhausted;
Some(last)
}
},
Self::Inclusive { start, end } => {
if *start <= *end {
match start.checked_add(&Idx::one()) {
Some(next) if next > *start && next <= *end => {
Some(mem::replace(start, next))
}
_ => {
let last = start.clone();
*self = Self::Exhausted;
Some(last)
}
}
} else {
*self = Self::Exhausted;
None
}
}
Self::Exclusive { inner } => {
if inner.start < inner.end {
match inner.start.checked_add(&Idx::one()) {
Some(next) if next > inner.start && next < inner.end => {
Some(mem::replace(&mut inner.start, next))
}
_ => {
let last = inner.start.clone();
*self = Self::Exhausted;
Some(last)
}
}
} else {
*self = Self::Exhausted;
None
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::Empty { .. } | Self::Exhausted => (0, Some(0)),
Self::From { .. } => (1, None),
Self::Inclusive { start, end } => {
if *start <= *end {
(1, None)
} else {
(0, Some(0))
}
}
Self::Exclusive { inner } => {
if inner.start < inner.end {
(1, None)
} else {
(0, Some(0))
}
}
}
}
}
impl<Idx> std::iter::FusedIterator for PartialRange<Idx> where
Idx: CheckedAdd + Clone + One + PartialOrd
{
}
impl<Idx> From<std::ops::Range<Idx>> for PartialRange<Idx> {
#[inline]
fn from(value: std::ops::Range<Idx>) -> Self {
Self::Exclusive { inner: value }
}
}
impl<Idx> From<std::ops::RangeFrom<Idx>> for PartialRange<Idx> {
#[inline]
fn from(value: std::ops::RangeFrom<Idx>) -> Self {
Self::From { inner: value }
}
}
impl<Idx: PartialOrd> From<std::ops::RangeInclusive<Idx>> for PartialRange<Idx> {
#[inline]
fn from(value: std::ops::RangeInclusive<Idx>) -> Self {
let empty = value.is_empty();
let (start, end) = value.into_inner();
if empty {
Self::Empty { idx: start }
} else {
Self::Inclusive { start, end }
}
}
}
impl<Idx> From<Range<Idx>> for PartialRange<Idx> {
#[inline]
fn from(value: Range<Idx>) -> Self {
match value.end {
RangeEnd::Inclusive(end) => Self::Inclusive {
start: value.start,
end,
},
RangeEnd::Exclusive(end) => Self::Exclusive {
inner: value.start..end,
},
}
}
}
impl<Idx> IntoIterator for Range<Idx>
where
Idx: CheckedAdd + Clone + One + PartialOrd,
{
type Item = Idx;
type IntoIter = PartialRange<Idx>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.into()
}
}