Skip to main content

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