pub trait AdventIterator: Iterator { fn into_chunks(self) -> impl Iterator> where Self: Sized, { in_chunks::(self) } } impl AdventIterator for I where I: Iterator {} #[derive(Debug, PartialEq, Eq)] pub enum Chunck { Next([T; N]), Rest(Vec), } pub fn in_chunks( mut iterator: impl Iterator, ) -> impl Iterator> { let mut buffer = Vec::new(); let mut done = false; std::iter::from_fn(move || { if done { return None; } for _ in 0..N { match iterator.next() { Some(to_push) => buffer.push(to_push), None => { done = true; return if buffer.is_empty() { None } else { Some(Chunck::Rest(std::mem::take(&mut buffer))) }; } } } let array: [T; N] = std::mem::take(&mut buffer) .try_into() .unwrap_or_else(|_| panic!("Buffer must have the same size as the N ({})", N)); Some(Chunck::Next(array)) }) } #[cfg(test)] mod testing { use crate::iterations::{in_chunks, Chunck}; #[test] fn should_split_chunks() { fn assert_case(input: Vec, expected: Vec>) { let actual: Vec> = in_chunks::(input.into_iter()).collect(); assert_eq!(expected, actual); } assert_case::<2>(vec![2], vec![Chunck::Rest(vec![2])]); assert_case::<2>(vec![], vec![]); assert_case::<2>(vec![2, 2], vec![Chunck::Next([2, 2])]); assert_case::<2>( vec![1, 2, 3], vec![Chunck::Next([1, 2]), Chunck::Rest(vec![3])], ); assert_case::<1>( vec![1, 2, 3], vec![Chunck::Next([1]), Chunck::Next([2]), Chunck::Next([3])], ); } }