use std::fmt::Debug;
use std::ops::{Add, AddAssign, Mul};
mod tests;
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Indexer<I, T> {
iter: I,
counter: T,
step: T
}
impl<I, T> Indexer<I, T> {
pub fn new(iter: I, start: T, step: T) -> Indexer<I, T> {
Indexer { iter, counter: start, step }
}
}
pub trait IndexerIterator {
fn index<T>(self) -> Indexer<Self, T> where Self: Sized, u8: Into<T> {
Indexer::new(self, 0.into(), 1.into())
}
fn index_start<T>(self, start: T) -> Indexer<Self, T> where Self: Sized, u8: Into<T> {
Indexer::new(self, start, 1.into())
}
fn index_step<T>(self, start: T, step: T) -> Indexer<Self, T> where Self: Sized {
Indexer::new(self, start, step)
}
}
impl<I, T> Iterator for Indexer<I, T>
where
I: Iterator,
T: Clone + for<'a> AddAssign<&'a T> + From<u8> + TryFrom<usize>,
for<'a> &'a T: Add<Output=T> + Mul<Output=T>,
<T as TryFrom<usize>>::Error: Debug,
{
type Item = (T, I::Item);
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some(v) => {
let result = Some((self.counter.clone(), v));
self.counter += &self.step;
result
}
None => None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
#[inline]
fn count(self) -> usize {
self.iter.count()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
let a = self.iter.nth(n)?;
let nn: T = n.try_into().unwrap_or_else(|_| panic!("Cannot convert n into {}", std::any::type_name::<T>()));
let i = &self.counter + &(&nn * &self.step);
self.counter = &i + &self.step;
Some((i.clone(), a))
}
}
impl<I, T> DoubleEndedIterator for Indexer<I, T>
where
I: ExactSizeIterator + DoubleEndedIterator,
T: Clone + Add<Output = T> + for<'a> AddAssign<&'a T> + From<u8> + TryFrom<usize>,
for<'a> &'a T: Add<Output=T> + Mul<Output=T>,
<T as TryFrom<usize>>::Error: Debug,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let item = self.iter.next_back()?;
let len = self.iter.len();
let len: T = len.try_into().unwrap_or_else(|_| panic!("Cannot convert len = {len} into {}", std::any::type_name::<T>()));
Some((self.counter.clone() + &len * &self.step, item))
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
let a = self.iter.nth_back(n)?;
let len = self.iter.len();
let len: T = len.try_into().unwrap_or_else(|_| panic!("Cannot convert len = {len} into {}", std::any::type_name::<T>()));
Some((self.counter.clone() + &len * &self.step, a))
}
}
impl<I, T> ExactSizeIterator for Indexer<I, T>
where
I: ExactSizeIterator,
T: Clone + for<'a> AddAssign<&'a T> + From<u8> + TryFrom<usize>,
for<'a> &'a T: Add<Output=T> + Mul<Output=T>,
<T as TryFrom<usize>>::Error: Debug,
{
fn len(&self) -> usize {
self.iter.len()
}
}
impl<I: Iterator> IndexerIterator for I {}