irox_tools/iterators/
mod.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2025 IROX Contributors
3//
4
5//!
6//! Iterators adds the [`Itertools`] Trait, which adds a number of additional
7//! helper methods to the [`Iterator`] Trait.
8//!
9
10extern crate alloc;
11use self::join::Joining;
12use self::looping_forever::LoopingForever;
13
14use crate::iterators::join::MultiJoining;
15use alloc::vec::Vec;
16
17mod join;
18pub mod looping_forever;
19mod streaming;
20mod zip;
21
22pub use streaming::*;
23pub use zip::*;
24
25///
26/// Itertools adds helpful additional methods to [`Iterator`]
27pub trait Itertools: Iterator {
28    ///
29    /// Returns an iterator that never ends, sequentially looping over all items in this
30    /// iterator forever, unless there are no items in the iterator.
31    fn looping_forever(self) -> LoopingForever<Self::Item>
32    where
33        Self: Sized + Iterator,
34        Self::Item: Clone,
35    {
36        LoopingForever {
37            index: 0,
38            items: self.collect(),
39        }
40    }
41
42    ///
43    /// Collects a specific amount of items from the iterator.  The underlying iterator may return
44    /// more, or less items than the specified count.  Any remaining uncollected items will be
45    /// discarded.  If count is greater than the length of the underlying iterator, then the
46    /// remainder of the returned vector will be None.
47    #[must_use]
48    fn collect_exact(mut self, count: usize) -> Vec<Option<Self::Item>>
49    where
50        Self: Sized + Iterator,
51        Self::Item: Clone,
52    {
53        let mut out: Vec<Option<Self::Item>> = Vec::with_capacity(count);
54        for _i in 0..count {
55            out.push(self.next())
56        }
57        out
58    }
59
60    ///
61    /// Same behavior as [`Itertools::collect_exact`], except rather than returning 'None' after the end, it
62    /// returns the specified value
63    #[must_use]
64    fn collect_exact_or(mut self, count: usize, def: Self::Item) -> Vec<Self::Item>
65    where
66        Self: Sized + Iterator,
67        Self::Item: Clone,
68    {
69        let mut out: Vec<Self::Item> = Vec::with_capacity(count);
70        for _i in 0..count {
71            out.push(self.next().unwrap_or(def.clone()))
72        }
73        out
74    }
75
76    ///
77    /// Same behavior as [`Itertools::collect_exact`], except rather than returning 'None' after the end, it
78    /// returns the default value
79    #[must_use]
80    fn collect_exact_or_default(mut self, count: usize) -> Vec<Self::Item>
81    where
82        Self: Sized + Iterator,
83        Self::Item: Clone + Default,
84    {
85        let mut out: Vec<Self::Item> = Vec::with_capacity(count);
86        for _i in 0..count {
87            out.push(self.next().unwrap_or_default());
88        }
89        out
90    }
91
92    ///
93    /// Collects and returns upto 'count' items from this iterator.  If this
94    /// iterator is exhausted, the returned vector is empty.  Note, the returned
95    /// vector may have *up to* the requested number of items if the iterator
96    /// exhausts before filling the chunk.
97    #[must_use]
98    fn collect_next_chunk(&mut self, count: usize) -> Vec<Self::Item> {
99        let mut out: Vec<Self::Item> = Vec::with_capacity(count);
100        for _i in 0..count {
101            match self.next() {
102                Some(e) => out.push(e),
103                None => break,
104            }
105        }
106        out
107    }
108
109    ///
110    /// Returns the elements in this iterator interspersed with the joining delimiter.
111    /// For example, if this iterator contains `[A, B, C, D]` and the delimiter is `z`, then the
112    /// final iteration sequence will be `[A, z, B, z, C, z, D]`
113    #[must_use]
114    fn joining(self, delim: Self::Item) -> Joining<Self, Self::Item>
115    where
116        Self: Sized,
117        Self::Item: Clone,
118    {
119        Joining::new(self, delim)
120    }
121
122    ///
123    /// Returns the elements in this iterator interspersed with the elements in the joining delimeter.
124    /// For example, if this iterator contains `[A, B, C, D]` and the delimiters are `[1, 2]`, then
125    /// the final iteration sequence will be `[A, 1, 2, B, 1, 2, C, 1, 2, D]`
126    #[must_use]
127    fn joining_multi(self, delim: &[Self::Item]) -> MultiJoining<Self, Self::Item>
128    where
129        Self: Sized,
130        Self::Item: Clone,
131    {
132        MultiJoining::new(self, delim)
133    }
134}
135
136impl<T: ?Sized> Itertools for T where T: Iterator {}
137
138pub struct Moderator {
139    start: usize,
140    modulus: usize,
141    max_count: usize,
142    idx: usize,
143}
144impl Moderator {
145    pub fn new(start: usize, modulus: usize) -> Self {
146        Self {
147            start,
148            modulus,
149            max_count: modulus,
150            idx: 0,
151        }
152    }
153    pub fn new_limited(start: usize, modulus: usize, max_count: usize) -> Self {
154        Self {
155            start,
156            modulus,
157            max_count,
158            idx: 0,
159        }
160    }
161}
162impl Iterator for Moderator {
163    type Item = usize;
164
165    fn next(&mut self) -> Option<Self::Item> {
166        if self.idx >= self.max_count {
167            return None;
168        }
169        let out = (self.start + self.idx) % self.modulus;
170        self.idx += 1;
171        Some(out)
172    }
173}
174
175#[cfg(test)]
176mod tests {
177    use crate::iterators::Moderator;
178
179    #[test]
180    pub fn test_moderator() {
181        let exp = &[0, 1, 2, 3, 4, 5];
182        let mut iter = Moderator::new(0, 6);
183        for e in exp {
184            assert_eq!(iter.next(), Some(*e));
185        }
186        assert_eq!(iter.next(), None);
187    }
188    #[test]
189    pub fn test_moderator2() {
190        let exp = &[3, 4, 5, 0, 1, 2];
191        let mut iter = Moderator::new(3, 6);
192        for e in exp {
193            assert_eq!(iter.next(), Some(*e));
194        }
195        assert_eq!(iter.next(), None);
196    }
197}