use core::iter::FusedIterator;
use crate::{IndexScalarType, IndexType};
#[cold]
#[inline(never)]
fn panic_typed_enumerate_overflow() -> ! {
panic!("typed enumerate index overflow")
}
#[derive(Debug, Clone)]
pub struct TypedEnumerate<I: IndexType, Iter> {
iter: Iter,
next_index: I,
}
impl<I: IndexType, Iter> TypedEnumerate<I, Iter> {
#[inline]
pub fn new(iter: Iter) -> Self {
Self {
iter,
next_index: I::ZERO,
}
}
}
impl<I: IndexType, Iter: Iterator> Iterator for TypedEnumerate<I, Iter> {
type Item = (I, Iter::Item);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let idx = self.next_index;
let next_index = idx
.checked_add_scalar(I::Scalar::ONE)
.unwrap_or_else(|_| panic_typed_enumerate_overflow());
let item = self.iter.next()?;
self.next_index = next_index;
Some((idx, item))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<I: IndexType, Iter: DoubleEndedIterator + ExactSizeIterator> DoubleEndedIterator
for TypedEnumerate<I, Iter>
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let remaining = self.iter.len();
if remaining == 0 {
return None;
}
let offset = I::Scalar::try_from_usize(unsafe { remaining.unchecked_sub(1) })
.unwrap_or_else(|| panic_typed_enumerate_overflow());
let idx = self
.next_index
.checked_add_scalar(offset)
.unwrap_or_else(|_| panic_typed_enumerate_overflow());
self.iter.next_back().map(|item| (idx, item))
}
}
impl<I: IndexType, Iter: ExactSizeIterator> ExactSizeIterator for TypedEnumerate<I, Iter> {
#[inline]
fn len(&self) -> usize {
self.iter.len()
}
}
impl<I: IndexType, Iter: FusedIterator> FusedIterator for TypedEnumerate<I, Iter> {}
#[derive(Debug, Clone)]
pub struct UncheckedTypedEnumerate<I: IndexType, Iter> {
iter: Iter,
next_index: I,
}
impl<I: IndexType, Iter> UncheckedTypedEnumerate<I, Iter> {
#[inline]
pub unsafe fn new(iter: Iter) -> Self {
Self {
iter,
next_index: I::ZERO,
}
}
}
impl<I: IndexType, Iter: Iterator> Iterator for UncheckedTypedEnumerate<I, Iter> {
type Item = (I, Iter::Item);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|item| {
let idx = self.next_index;
self.next_index = unsafe { self.next_index.unchecked_add_scalar(I::Scalar::ONE) };
(idx, item)
})
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<I: IndexType, Iter: DoubleEndedIterator + ExactSizeIterator> DoubleEndedIterator
for UncheckedTypedEnumerate<I, Iter>
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let remaining = self.iter.len();
if remaining == 0 {
return None;
}
let offset = unsafe { I::Scalar::from_usize_unchecked(remaining.unchecked_sub(1)) };
let idx = unsafe { self.next_index.unchecked_add_scalar(offset) };
self.iter.next_back().map(|item| (idx, item))
}
}
impl<I: IndexType, Iter: ExactSizeIterator> ExactSizeIterator for UncheckedTypedEnumerate<I, Iter> {
#[inline]
fn len(&self) -> usize {
self.iter.len()
}
}
impl<I: IndexType, Iter: FusedIterator> FusedIterator for UncheckedTypedEnumerate<I, Iter> {}
pub trait TypedIteratorExt: Iterator + Sized {
#[inline]
fn typed_enumerate<I: IndexType>(self) -> TypedEnumerate<I, Self> {
TypedEnumerate::new(self)
}
#[inline]
unsafe fn typed_enumerate_unchecked<I: IndexType>(self) -> UncheckedTypedEnumerate<I, Self> {
unsafe { UncheckedTypedEnumerate::new(self) }
}
}
impl<Iter: Iterator> TypedIteratorExt for Iter {}