2 use crate::iter::{ByRefSized, FusedIterator, Iterator};
3 use crate::ops::{ControlFlow, Try};
5 /// An iterator over `N` elements of the iterator at a time.
7 /// The chunks do not overlap. If `N` does not divide the length of the
8 /// iterator, then the last up to `N-1` elements will be omitted.
10 /// This `struct` is created by the [`array_chunks`][Iterator::array_chunks]
11 /// method on [`Iterator`]. See its documentation for more.
12 #[derive(Debug, Clone)]
13 #[must_use = "iterators are lazy and do nothing unless consumed"]
14 #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
15 pub struct ArrayChunks<I: Iterator, const N: usize> {
17 remainder: Option<array::IntoIter<I::Item, N>>,
20 impl<I, const N: usize> ArrayChunks<I, N>
25 pub(in crate::iter) fn new(iter: I) -> Self {
26 assert!(N != 0, "chunk size must be non-zero");
27 Self { iter, remainder: None }
30 /// Returns an iterator over the remaining elements of the original iterator
31 /// that are not going to be returned by this iterator. The returned
32 /// iterator will yield at most `N-1` elements.
33 #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
35 pub fn into_remainder(self) -> Option<array::IntoIter<I::Item, N>> {
40 #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
41 impl<I, const N: usize> Iterator for ArrayChunks<I, N>
45 type Item = [I::Item; N];
48 fn next(&mut self) -> Option<Self::Item> {
49 self.try_for_each(ControlFlow::Break).break_value()
53 fn size_hint(&self) -> (usize, Option<usize>) {
54 let (lower, upper) = self.iter.size_hint();
56 (lower / N, upper.map(|n| n / N))
60 fn count(self) -> usize {
64 fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
67 F: FnMut(B, Self::Item) -> R,
72 match self.iter.next_chunk() {
73 Ok(chunk) => acc = f(acc, chunk)?,
75 // Make sure to not override `self.remainder` with an empty array
76 // when `next` is called after `ArrayChunks` exhaustion.
77 self.remainder.get_or_insert(remainder);
85 impl_fold_via_try_fold! { fold -> try_fold }
88 #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
89 impl<I, const N: usize> DoubleEndedIterator for ArrayChunks<I, N>
91 I: DoubleEndedIterator + ExactSizeIterator,
94 fn next_back(&mut self) -> Option<Self::Item> {
95 self.try_rfold((), |(), x| ControlFlow::Break(x)).break_value()
98 fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
101 F: FnMut(B, Self::Item) -> R,
104 // We are iterating from the back we need to first handle the remainder.
105 self.next_back_remainder();
108 let mut iter = ByRefSized(&mut self.iter).rev();
110 // NB remainder is handled by `next_back_remainder`, so
111 // `next_chunk` can't return `Err` with non-empty remainder
112 // (assuming correct `I as ExactSizeIterator` impl).
113 while let Ok(mut chunk) = iter.next_chunk() {
114 // FIXME: do not do double reverse
115 // (we could instead add `next_chunk_back` for example)
123 impl_fold_via_try_fold! { rfold -> try_rfold }
126 impl<I, const N: usize> ArrayChunks<I, N>
128 I: DoubleEndedIterator + ExactSizeIterator,
130 /// Updates `self.remainder` such that `self.iter.len` is divisible by `N`.
131 fn next_back_remainder(&mut self) {
132 // Make sure to not override `self.remainder` with an empty array
133 // when `next_back` is called after `ArrayChunks` exhaustion.
134 if self.remainder.is_some() {
138 // We use the `ExactSizeIterator` implementation of the underlying
139 // iterator to know how many remaining elements there are.
140 let rem = self.iter.len() % N;
142 // Take the last `rem` elements out of `self.iter`.
144 // SAFETY: `unwrap_err` always succeeds because x % N < N for all x.
145 unsafe { self.iter.by_ref().rev().take(rem).next_chunk().unwrap_err_unchecked() };
147 // We used `.rev()` above, so we need to re-reverse the reminder
148 remainder.as_mut_slice().reverse();
149 self.remainder = Some(remainder);
153 #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
154 impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {}
156 #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
157 impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N>
159 I: ExactSizeIterator,
162 fn len(&self) -> usize {
167 fn is_empty(&self) -> bool {