Skip to main content

aoc/util/
iter.rs

1//! Add a `chunk` method to [`Iterator`] that duplicates the functionality of the unstable
2//! [`array_chunks`] method.
3//!
4//! Using Rust's const generics, concrete implementations are provided for sizes 2 to 12 to handle
5//! the most common situations. Once [`array_chunks`] is stabilized this module can be removed.
6//!
7//! [`array_chunks`]: std::iter::Iterator::array_chunks
8pub struct Chunk<I, const N: usize> {
9    iter: I,
10}
11
12pub trait ChunkExt: Iterator + Sized {
13    #[must_use]
14    fn chunk<const N: usize>(self) -> Chunk<Self, N>;
15}
16
17impl<I: Iterator> ChunkExt for I {
18    fn chunk<const N: usize>(self) -> Chunk<Self, N> {
19        Chunk { iter: self }
20    }
21}
22
23macro_rules! iterator {
24    ($n:literal $($var:ident)+) => {
25        impl<I: Iterator> Iterator for Chunk<I, $n> {
26            type Item = [I::Item; $n];
27
28            #[inline]
29            fn size_hint(&self) -> (usize, Option<usize>) {
30                let (lo, hi) = self.iter.size_hint();
31                (lo / $n, hi.map(|h| h / $n))
32            }
33
34            #[inline]
35            fn next(&mut self) -> Option<Self::Item> {
36                $(let $var = self.iter.next()?;)+
37                Some([$($var),+])
38            }
39        }
40    };
41}
42
43iterator!(2 a b);
44iterator!(3 a b c);
45iterator!(4 a b c d);
46iterator!(5 a b c d e);
47iterator!(6 a b c d e f);
48iterator!(7 a b c d e f g);
49iterator!(8 a b c d e f g h);
50iterator!(9 a b c d e f g h i);
51iterator!(10 a b c d e f g h i j);
52iterator!(11 a b c d e f g h i j k);
53iterator!(12 a b c d e f g h i j k l);