1use std::iter::Iterator;
2
3pub trait IterChunks: Sized + Iterator {
5 fn chunks(self, n: usize) -> Chunks<Self>;
25}
26
27impl<I> IterChunks for I
28where
29 I: Iterator,
30{
31 fn chunks(self, n: usize) -> Chunks<Self> {
32 assert_ne!(n, 0);
33 Chunks {
34 inner: self,
35 n,
36 end_flag: false,
37 }
38 }
39}
40
41pub struct Chunks<I: Iterator> {
48 inner: I,
49 n: usize,
50 end_flag: bool,
51}
52
53impl<I: Iterator> Chunks<I> {
54 #[allow(clippy::should_implement_trait)]
61 pub fn next(&mut self) -> Option<Chunk<'_, I>> {
62 if self.end_flag {
63 self.end_flag = false;
65 None
66 } else {
67 match self.inner.next() {
68 Some(v) => {
69 let n = self.n;
70 Some(Chunk {
71 first: Some(v),
72 parent: self,
73 n: n - 1,
74 })
75 }
76 None => None,
77 }
78 }
79 }
80
81 pub fn for_each(&mut self, mut f: impl FnMut(Chunk<'_, I>)) {
92 while let Some(item) = self.next() {
93 f(item)
94 }
95 }
96}
97
98pub struct Chunk<'a, I: Iterator> {
105 first: Option<I::Item>,
106 parent: &'a mut Chunks<I>,
107 n: usize,
108}
109
110impl<'a, I> Iterator for Chunk<'a, I>
111where
112 I: Iterator,
113{
114 type Item = <I as Iterator>::Item;
115
116 fn next(&mut self) -> Option<Self::Item> {
117 match self.first.take() {
118 Some(v) => Some(v),
119 None if self.n > 0 => {
120 self.n -= 1;
121 match self.parent.inner.next() {
122 Some(v) => Some(v),
123 None => {
124 self.n = 0;
126
127 self.parent.end_flag = true;
129
130 None
131 }
132 }
133 }
134 None => None,
135 }
136 }
137
138 fn size_hint(&self) -> (usize, Option<usize>) {
139 let (lower, upper) = self.parent.inner.size_hint();
140 let has_first = self.first.is_some() as usize;
141 let n = self.n;
142 let lower = lower.min(n) + has_first;
145 let upper = upper.map(|v| v.min(n) + has_first);
146 (lower, upper)
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::IterChunks;
153
154 #[test]
155 fn test_impls() {
156 let chunks = [0i32].into_iter().chunks(1);
157
158 fn assert_send<T: Send>(_: &T) {}
160 fn assert_sync<T: Sync>(_: &T) {}
162
163 assert_sync(&chunks);
164 assert_send(&chunks);
165 }
166
167 #[test]
168 fn test_chunks() {
169 let arr = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3];
170 let mut i = 0;
171 let mut chunks = arr.into_iter().chunks(3);
172
173 while let Some(chunk) = chunks.next() {
174 for v in chunk {
175 assert_eq!(v, i);
176 }
177 i += 1;
178 }
179 assert_eq!(i, 4);
180 }
181
182 #[test]
183 fn test_chunk_resumable() {
184 let inner_gen = |rem| {
185 let mut i = 0;
186 std::iter::from_fn(move || {
187 i += 1;
188 if i % rem == 0 {
189 None
190 } else {
191 Some(i)
192 }
193 })
194 };
195
196 let inner = inner_gen(3);
197 let mut chunks = inner.chunks(4);
198 while let Some(chunk) = chunks.next() {
199 assert_eq!(chunk.collect::<Vec<_>>(), vec![1, 2]);
200 }
201 while let Some(chunk) = chunks.next() {
202 assert_eq!(chunk.collect::<Vec<_>>(), vec![4, 5]);
203 }
204 while let Some(chunk) = chunks.next() {
205 assert_eq!(chunk.collect::<Vec<_>>(), vec![7, 8]);
206 }
207
208 let inner = inner_gen(6);
209 let mut chunks = inner.chunks(4);
210
211 assert_eq!(chunks.next().unwrap().collect::<Vec<_>>(), vec![1, 2, 3, 4]);
212 assert_eq!(chunks.next().unwrap().collect::<Vec<_>>(), vec![5]);
213 assert!(chunks.next().is_none());
214
215 assert_eq!(
216 chunks.next().unwrap().collect::<Vec<_>>(),
217 vec![7, 8, 9, 10]
218 );
219 assert_eq!(chunks.next().unwrap().collect::<Vec<_>>(), vec![11]);
220 assert!(chunks.next().is_none());
221 }
222
223 #[test]
224 fn test_chunks_count() {
225 let arr: [bool; 0] = [];
226 let mut i = 0;
227 let mut chunks = arr.into_iter().chunks(3);
228
229 while let Some(chunk) = chunks.next() {
230 for _ in chunk {}
231 i += 1;
232 }
233 assert_eq!(i, 0);
234
235 let arr: [bool; 3] = [false; 3];
236 let mut i = 0;
237 let mut chunks = arr.into_iter().chunks(3);
238
239 while let Some(chunk) = chunks.next() {
240 for _ in chunk {}
241 i += 1;
242 }
243 assert_eq!(i, 1);
244 }
245
246 #[test]
247 fn test_size_hint() {
248 let iter = [1, 2, 3, 4]
249 .into_iter()
250 .chain([5, 6, 7].into_iter().filter(|_| true));
251 let (lower, upper) = iter.size_hint();
252 assert_eq!(lower, 4);
253 assert_eq!(upper, Some(7));
254 let mut chunks = iter.chunks(3);
255
256 let mut chunk1 = chunks.next().unwrap();
257
258 assert_eq!(chunk1.size_hint(), (3, Some(3)));
259 chunk1.next().unwrap();
260 assert_eq!(chunk1.size_hint(), (2, Some(2)));
261
262 for _ in chunk1 {}
263
264 let chunk2 = chunks.next().unwrap();
265 assert_eq!(chunk2.size_hint(), (1, Some(3)));
266 for _ in chunk2 {}
267
268 let mut chunk3 = chunks.next().unwrap();
269 assert_eq!(chunk3.size_hint(), (1, Some(1)));
270 chunk3.next().unwrap();
271 assert_eq!(chunk3.size_hint(), (0, Some(0)));
272 }
273}