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 then this module can be removed.
6//!
7//! [`array_chunks`]: std::iter::Iterator::array_chunks
8pub struct Chunk<I: Iterator, const N: usize> {
9    iter: I,
10}
11
12pub trait ChunkOps: Iterator + Sized {
13    fn chunk<const N: usize>(self) -> Chunk<Self, N>;
14}
15
16impl<I: Iterator> ChunkOps for I {
17    fn chunk<const N: usize>(self) -> Chunk<Self, N> {
18        Chunk { iter: self }
19    }
20}
21
22macro_rules! iterator {
23    ($n:literal, $($var:ident),+) => {
24        impl<I: Iterator> Iterator for Chunk<I, $n> {
25            type Item = [I::Item; $n];
26
27            #[inline]
28            fn size_hint(&self) -> (usize, Option<usize>) {
29                let (lo, hi) = self.iter.size_hint();
30                (lo / $n, hi.map(|h| h / $n))
31            }
32
33            #[inline]
34            fn next(&mut self) -> Option<Self::Item> {
35                Some([$({
36                    let $var = self.iter.next()?;
37                    $var
38                }),+])
39            }
40        }
41    };
42}
43
44iterator!(2, a, b);
45iterator!(3, a, b, c);
46iterator!(4, a, b, c, d);
47iterator!(5, a, b, c, d, e);
48iterator!(6, a, b, c, d, e, f);
49iterator!(7, a, b, c, d, e, f, g);
50iterator!(8, a, b, c, d, e, f, g, h);
51iterator!(9, a, b, c, d, e, f, g, h, i);
52iterator!(10, a, b, c, d, e, f, g, h, i, j);
53iterator!(11, a, b, c, d, e, f, g, h, i, j, k);
54iterator!(12, a, b, c, d, e, f, g, h, i, j, k, l);