use core::iter::FusedIterator;
use crate::{IndexScalarType, IndexType};
pub trait TypedRangeIterExt<I: IndexType> {
type Iter: Iterator<Item = I>;
fn iter(self) -> Self::Iter;
}
impl<I: IndexType> TypedRangeIterExt<I> for core::ops::Range<I> {
type Iter = TypedRangeIter<I>;
#[inline]
fn iter(self) -> Self::Iter {
TypedRangeIter::from_raw(self)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct TypedRangeIter<I: IndexType> {
pub start: I,
pub end: I,
}
impl<I: IndexType + core::fmt::Debug> core::fmt::Debug for TypedRangeIter<I> {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(fmt, "{:?}..{:?}", self.start, self.end)
}
}
impl<I: IndexType> TypedRangeIter<I> {
#[inline]
pub const fn into_raw(self) -> core::ops::Range<I> {
self.start..self.end
}
#[inline]
pub const fn from_raw(value: core::ops::Range<I>) -> Self {
Self {
start: value.start,
end: value.end,
}
}
#[inline]
pub fn len(&self) -> usize {
self.end
.checked_sub_index(self.start)
.unwrap_or(I::Scalar::ZERO)
.to_usize()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.start >= self.end
}
}
impl<I: IndexType> From<core::ops::Range<I>> for TypedRangeIter<I> {
fn from(value: core::ops::Range<I>) -> Self {
Self::from_raw(value)
}
}
impl<I: IndexType> Iterator for TypedRangeIter<I> {
type Item = I;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.start >= self.end {
return None;
}
let res = self.start;
self.start = unsafe { res.unchecked_add_scalar(I::Scalar::ONE) };
Some(res)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
#[inline]
fn count(self) -> usize {
self.len()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<I> {
let Some(offset) = I::Scalar::try_from_usize(n) else {
self.start = self.end;
return None;
};
let Ok(res) = self.start.checked_add_scalar(offset) else {
self.start = self.end;
return None;
};
if res >= self.end {
self.start = self.end;
return None;
}
self.start = unsafe { res.unchecked_add_scalar(I::Scalar::ONE) };
Some(res)
}
#[inline]
fn last(mut self) -> Option<I> {
self.next_back()
}
#[inline]
fn min(mut self) -> Option<I>
where
I: Ord,
{
self.next()
}
#[inline]
fn max(mut self) -> Option<I>
where
I: Ord,
{
self.next_back()
}
#[inline]
fn is_sorted(self) -> bool {
true
}
}
impl<I: IndexType> DoubleEndedIterator for TypedRangeIter<I> {
#[inline]
fn next_back(&mut self) -> Option<I> {
if self.start >= self.end {
return None;
}
let res = unsafe { self.end.unchecked_sub_scalar(I::Scalar::ONE) };
self.end = res;
Some(res)
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<I> {
let Some(offset) = I::Scalar::try_from_usize(n) else {
self.end = self.start;
return None;
};
let Some(res) = self
.end
.checked_sub_scalar(offset)
.and_then(|x| x.checked_sub_scalar(I::Scalar::ONE))
else {
self.end = self.start;
return None;
};
if res < self.start {
self.end = self.start;
return None;
}
self.end = res;
Some(res)
}
}
impl<I: IndexType> ExactSizeIterator for TypedRangeIter<I> {
#[inline]
fn len(&self) -> usize {
TypedRangeIter::len(self)
}
}
impl<I: IndexType> FusedIterator for TypedRangeIter<I> {}
impl<I: IndexType> TypedRangeIterExt<I> for core::ops::RangeFrom<I> {
type Iter = TypedRangeFromIter<I>;
#[inline]
fn iter(self) -> Self::Iter {
TypedRangeFromIter::from_raw(self)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct TypedRangeFromIter<I: IndexType> {
pub start: I,
}
impl<I: IndexType + core::fmt::Debug> core::fmt::Debug for TypedRangeFromIter<I> {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(fmt, "{:?}..", self.start)
}
}
impl<I: IndexType> TypedRangeFromIter<I> {
#[inline]
pub const fn into_raw(self) -> core::ops::RangeFrom<I> {
self.start..
}
#[inline]
pub const fn from_raw(value: core::ops::RangeFrom<I>) -> Self {
Self { start: value.start }
}
}
impl<I: IndexType> From<core::ops::RangeFrom<I>> for TypedRangeFromIter<I> {
fn from(value: core::ops::RangeFrom<I>) -> Self {
Self::from_raw(value)
}
}
#[cold]
#[inline(never)]
#[track_caller]
fn panic_range_from_index_overflow() -> ! {
panic!("range-from index overflow")
}
impl<I: IndexType> Iterator for TypedRangeFromIter<I> {
type Item = I;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let res = self.start;
self.start = res
.checked_add_scalar(I::Scalar::ONE)
.unwrap_or_else(|_| panic_range_from_index_overflow());
Some(res)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::MAX, None)
}
#[inline]
fn nth(&mut self, n: usize) -> Option<I> {
let res = self
.start
.checked_add_scalar(
I::Scalar::try_from_usize(n).unwrap_or_else(|| panic_range_from_index_overflow()),
)
.unwrap_or_else(|_| panic_range_from_index_overflow());
self.start = res
.checked_add_scalar(I::Scalar::ONE)
.unwrap_or_else(|_| panic_range_from_index_overflow());
Some(res)
}
#[inline]
fn min(mut self) -> Option<I>
where
I: Ord,
{
self.next()
}
#[inline]
fn is_sorted(self) -> bool {
true
}
}
impl<I: IndexType> FusedIterator for TypedRangeFromIter<I> {}
impl<I: IndexType> TypedRangeIterExt<I> for core::ops::RangeInclusive<I> {
type Iter = TypedRangeInclusiveIter<I>;
#[inline]
fn iter(self) -> Self::Iter {
TypedRangeInclusiveIter::from_raw(self)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct TypedRangeInclusiveIter<I: IndexType> {
start: I,
end: I,
exhausted: bool,
}
impl<I: IndexType + core::fmt::Debug> core::fmt::Debug for TypedRangeInclusiveIter<I> {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(fmt, "{:?}..={:?}", self.start, self.end)?;
if self.exhausted {
write!(fmt, " (exhausted)")?;
}
Ok(())
}
}
impl<I: IndexType> TypedRangeInclusiveIter<I> {
#[inline]
pub const fn into_raw(self) -> core::ops::RangeInclusive<I> {
self.start..=self.end
}
#[inline]
pub const fn from_raw(range: core::ops::RangeInclusive<I>) -> Self {
Self {
start: *range.start(),
end: *range.end(),
exhausted: false,
}
}
#[inline]
pub const fn start(&self) -> I {
self.start
}
#[inline]
pub const fn end(&self) -> I {
self.end
}
#[inline]
pub fn is_empty(&self) -> bool {
self.exhausted || self.start > self.end
}
#[inline]
pub fn try_len(&self) -> Option<usize> {
if self.exhausted {
return Some(0);
}
let Some(diff) = self.end.checked_sub_index(self.start) else {
return Some(0);
};
diff.to_usize().checked_add(1)
}
#[inline]
pub fn len(&self) -> usize {
self.try_len()
.expect("inclusive range length overflowed usize")
}
}
impl<I: IndexType> From<core::ops::RangeInclusive<I>> for TypedRangeInclusiveIter<I> {
fn from(value: core::ops::RangeInclusive<I>) -> Self {
Self::from_raw(value)
}
}
impl<I: IndexType> Iterator for TypedRangeInclusiveIter<I> {
type Item = I;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if TypedRangeInclusiveIter::is_empty(self) {
return None;
}
let res = self.start;
match self.start.checked_add_scalar(I::Scalar::ONE) {
Ok(start_plus_1) => self.start = start_plus_1,
Err(_) => self.exhausted = true,
}
Some(res)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match self.try_len() {
Some(len) => (len, Some(len)),
None => {
(usize::MAX, None)
}
}
}
#[inline]
fn count(self) -> usize {
self.len()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<I> {
if TypedRangeInclusiveIter::is_empty(self) {
return None;
}
let Some(offset) = I::Scalar::try_from_usize(n) else {
self.exhausted = true;
return None;
};
let Ok(res) = self.start.checked_add_scalar(offset) else {
self.exhausted = true;
return None;
};
if res > self.end {
self.exhausted = true;
return None;
}
match res.checked_add_scalar(I::Scalar::ONE) {
Ok(res_plus_1) => {
self.start = res_plus_1;
}
Err(_) => {
self.exhausted = true;
}
}
Some(res)
}
#[inline]
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
#[inline]
fn min(mut self) -> Option<Self::Item>
where
I: Ord,
{
self.next()
}
#[inline]
fn max(mut self) -> Option<Self::Item>
where
I: Ord,
{
self.next_back()
}
#[inline]
fn is_sorted(self) -> bool {
true
}
}
impl<I: IndexType> DoubleEndedIterator for TypedRangeInclusiveIter<I> {
#[inline]
fn next_back(&mut self) -> Option<I> {
if TypedRangeInclusiveIter::is_empty(self) {
return None;
}
let res = self.end;
match self.end.checked_sub_scalar(I::Scalar::ONE) {
Some(end_minus_1) => {
self.end = end_minus_1;
}
None => {
self.exhausted = true;
}
};
Some(res)
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<I> {
if TypedRangeInclusiveIter::is_empty(self) {
return None;
}
let Some(offset) = I::Scalar::try_from_usize(n) else {
self.exhausted = true;
return None;
};
let Some(res) = self.end.checked_sub_scalar(offset) else {
self.exhausted = true;
return None;
};
if res < self.start {
self.exhausted = true;
return None;
}
match res.checked_sub_scalar(I::Scalar::ONE) {
Some(res_minus_1) => {
self.end = res_minus_1;
}
None => {
self.exhausted = true;
}
}
Some(res)
}
}
impl<I: IndexType> FusedIterator for TypedRangeInclusiveIter<I> {}