iter_index/
lib.rs

1// Copyright 2025 Redglyph
2//
3
4//! This crate provides a simple extension trait that provides a more flexible alternative to the iterator's method `enumerate()`.
5//!
6//! It allows to:
7//!  * use a custom type for the index with `index::<T>()`
8//!  * define a custom start value with `index_start::<T>(start: T)`
9//!  * define a custom step value with `index_step::<T>(start: T, step: T)`.
10//!
11//! ```rust
12//! use iter_index::IndexerIterator;
13//!
14//! let items = vec!["a", "b", "c"];
15//! let result = items.iter().index::<i32>().collect::<Vec<_>>();
16//! assert_eq!(result, vec![(0_i32, &"a"), (1_i32, &"b"), (2_i32, &"c")]);
17//!
18//! let result = items.iter().index_start::<u8>(97).collect::<Vec<_>>();
19//! assert_eq!(result, vec![(97_u8, &"a"), (98_u8, &"b"), (99_u8, &"c")]);
20//!
21//! let result = items.into_iter().index_step::<i16>(100, 10).collect::<Vec<_>>();
22//! assert_eq!(result, vec![(100_i16, "a"), (110_i16, "b"), (120_i16, "c")]);
23//!
24//! let items = 'a'..='z';
25//! let mut result = items.index_step(100, 10);
26//! assert_eq!(result.next(), Some((100, 'a')));
27//! assert_eq!(result.nth(5), Some((160, 'g')));
28//! ```
29
30use std::fmt::Debug;
31use std::ops::{Add, AddAssign, Mul};
32
33mod tests;
34
35//------------------------------------------------------------------------------
36
37/// An iterator that yields the current count, with the generic type, and the iteration item.
38#[derive(Clone, Debug)]
39#[must_use = "iterators are lazy and do nothing unless consumed"]
40pub struct Indexer<I, T> {
41    iter: I,
42    counter: T,
43    step: T
44}
45
46impl<I, T> Indexer<I, T> {
47    pub fn new(iter: I, start: T, step: T) -> Indexer<I, T> {
48        Indexer { iter, counter: start, step  }
49    }
50}
51
52pub trait IndexerIterator {
53    /// Creates an iterator which gives an index of the source iterator value as well as the value itself.
54    ///
55    /// The iterator yields pairs `(i, val)`, where `i` is of type `T` and contains the current
56    /// index of iteration, and `val` is the value returned by the source iterator.
57    ///
58    /// `index::<T>()` starts counting at 0 and increments by 1. If you need another start value, use
59    /// `index_start::<T>(start: T)` instead. If you need different steps than 1, use
60    /// `index_step::<T>(start: T, step: T)`.
61    ///
62    /// # Overflow Behavior
63    ///
64    /// The method does no guarding against overflows, so you may have to prevent it, depending on the type `T`
65    /// and the number of items generated by the source iterator.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// use iter_index::IndexerIterator;
71    ///
72    /// let items = vec!["a", "b", "c"];
73    /// let mut result = items.into_iter().index::<i32>();
74    ///
75    /// assert_eq!(result.next(), Some((0_i32, "a")));
76    /// assert_eq!(result.next(), Some((1_i32, "b")));
77    /// assert_eq!(result.next(), Some((2_i32, "c")));
78    /// assert_eq!(result.next(), None);
79    /// ```
80    fn index<T>(self) -> Indexer<Self, T> where Self: Sized, u8: Into<T> {
81        Indexer::new(self, 0.into(), 1.into())
82    }
83
84    /// Creates an iterator which gives an index of the source iterator value as well as the value itself.
85    ///
86    /// The iterator yields pairs `(i, val)`, where `i` is of type `T` and contains the current
87    /// index of iteration, and `val` is the value returned by the source iterator.
88    ///
89    /// `index_start::<T>(start: T)` starts counting at `start` and increments by 1. If you need different
90    /// steps than 1, use `index_step::<T>(start: T, step: T)`.
91    ///
92    /// # Overflow Behavior
93    ///
94    /// The method does no guarding against overflows, so you may have to prevent it, depending on the type `T`
95    /// and the number of items generated by the source iterator.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// use iter_index::IndexerIterator;
101    ///
102    /// let items = vec!["a", "b", "c"];
103    /// let mut result = items.into_iter().index_start::<u8>(97);
104    ///
105    /// assert_eq!(result.next(), Some((97_u8, "a")));
106    /// assert_eq!(result.next(), Some((98_u8, "b")));
107    /// assert_eq!(result.next(), Some((99_u8, "c")));
108    /// assert_eq!(result.next(), None);
109    /// ```
110    fn index_start<T>(self, start: T) -> Indexer<Self, T> where Self: Sized, u8: Into<T> {
111        Indexer::new(self, start, 1.into())
112    }
113
114    /// Creates an iterator which gives an index of the source iterator value as well as the value itself.
115    ///
116    /// The iterator yields pairs `(i, val)`, where `i` is of type `T` and contains the current
117    /// index of iteration, and `val` is the value returned by the source iterator.
118    ///
119    /// `index_step::<T>(start: T, step: T)` starts counting at `start` and increments by `step`.
120    ///
121    /// # Overflow Behavior
122    ///
123    /// The method does no guarding against overflows, so you may have to prevent it, depending on the type `T`
124    /// and the number of items generated by the source iterator.
125    ///
126    /// # Examples
127    ///
128    /// ```
129    /// use iter_index::IndexerIterator;
130    ///
131    /// let items = vec!["a", "b", "c"];
132    /// let mut result = items.into_iter().index_step::<u32>(100, 10);
133    ///
134    /// assert_eq!(result.next(), Some((100_u32, "a")));
135    /// assert_eq!(result.next(), Some((110_u32, "b")));
136    /// assert_eq!(result.next(), Some((120_u32, "c")));
137    /// assert_eq!(result.next(), None);
138    /// ```
139    fn index_step<T>(self, start: T, step: T) -> Indexer<Self, T> where Self: Sized {
140        Indexer::new(self, start, step)
141    }
142}
143
144//------------------------------------------------------------------------------
145// Iterator methods
146
147impl<I, T> Iterator for Indexer<I, T>
148where
149    I: Iterator,
150    T: Clone + for<'a> AddAssign<&'a T> + From<u8> + TryFrom<usize>,
151    for<'a> &'a T: Add<Output=T> + Mul<Output=T>,
152    <T as TryFrom<usize>>::Error: Debug,
153{
154    type Item = (T, I::Item);
155
156    fn next(&mut self) -> Option<Self::Item> {
157        match self.iter.next() {
158            Some(v) => {
159                let result = Some((self.counter.clone(), v));
160                self.counter += &self.step;
161                result
162            }
163            None => None
164        }
165    }
166
167    #[inline]
168    fn size_hint(&self) -> (usize, Option<usize>) {
169        self.iter.size_hint()
170    }
171
172    #[inline]
173    fn count(self) -> usize {
174        self.iter.count()
175    }
176
177    #[inline]
178    fn nth(&mut self, n: usize) -> Option<Self::Item> {
179        let a = self.iter.nth(n)?;
180        let nn: T = n.try_into().unwrap_or_else(|_| panic!("Cannot convert n into {}", std::any::type_name::<T>()));
181        let i = &self.counter + &(&nn * &self.step);
182        self.counter = &i + &self.step;
183        Some((i.clone(), a))
184    }
185}
186
187//------------------------------------------------------------------------------
188// DoubleEndedIterator methods
189
190impl<I, T> DoubleEndedIterator for Indexer<I, T>
191where
192    I: ExactSizeIterator + DoubleEndedIterator,
193    T: Clone + Add<Output = T> + for<'a> AddAssign<&'a T> + From<u8> + TryFrom<usize>,
194    for<'a> &'a T: Add<Output=T> + Mul<Output=T>,
195    <T as TryFrom<usize>>::Error: Debug,
196{
197    #[inline]
198    fn next_back(&mut self) -> Option<Self::Item> {
199        let item = self.iter.next_back()?;
200        let len = self.iter.len();
201        let len: T = len.try_into().unwrap_or_else(|_| panic!("Cannot convert len = {len} into {}", std::any::type_name::<T>()));
202        // counter + len * step must not overflow for T
203        Some((self.counter.clone() + &len * &self.step, item))
204    }
205
206    #[inline]
207    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
208        let a = self.iter.nth_back(n)?;
209        let len = self.iter.len();
210        let len: T = len.try_into().unwrap_or_else(|_| panic!("Cannot convert len = {len} into {}", std::any::type_name::<T>()));
211        // counter + len * step must not overflow for T
212        Some((self.counter.clone() + &len * &self.step, a))
213    }
214}
215
216//------------------------------------------------------------------------------
217
218impl<I, T> ExactSizeIterator for Indexer<I, T>
219where
220    I: ExactSizeIterator,
221    T: Clone + for<'a> AddAssign<&'a T> + From<u8> + TryFrom<usize>,
222    for<'a> &'a T: Add<Output=T> + Mul<Output=T>,
223    <T as TryFrom<usize>>::Error: Debug,
224{
225    fn len(&self) -> usize {
226        self.iter.len()
227    }
228}
229
230//------------------------------------------------------------------------------
231// Blanket implementation
232
233impl<I: Iterator> IndexerIterator for I {}
234