1use crate::array;
2use crate::iter::adapters::SourceIter;
3use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedRandomAccessNoCoerce};
4use crate::num::NonZero;
5use crate::ops::{ControlFlow, NeverShortCircuit, Try};
6
7#[derive(Debug, Clone)]
15#[must_use = "iterators are lazy and do nothing unless consumed"]
16#[unstable(feature = "iter_array_chunks", issue = "100450")]
17pub struct ArrayChunks<I: Iterator, const N: usize> {
18 iter: I,
19 remainder: Option<array::IntoIter<I::Item, N>>,
20}
21
22impl<I, const N: usize> ArrayChunks<I, N>
23where
24 I: Iterator,
25{
26 #[track_caller]
27 pub(in crate::iter) const fn new(iter: I) -> Self {
28 assert!(N != 0, "chunk size must be non-zero");
29 Self { iter, remainder: None }
30 }
31
32 #[unstable(feature = "iter_array_chunks", issue = "100450")]
46 #[inline]
47 pub fn into_remainder(mut self) -> array::IntoIter<I::Item, N> {
48 if self.remainder.is_none() {
49 while let Some(_) = self.next() {}
50 }
51 self.remainder.unwrap_or_default()
52 }
53}
54
55#[unstable(feature = "iter_array_chunks", issue = "100450")]
56impl<I, const N: usize> Iterator for ArrayChunks<I, N>
57where
58 I: Iterator,
59{
60 type Item = [I::Item; N];
61
62 #[inline]
63 fn next(&mut self) -> Option<Self::Item> {
64 self.try_for_each(ControlFlow::Break).break_value()
65 }
66
67 #[inline]
68 fn size_hint(&self) -> (usize, Option<usize>) {
69 let (lower, upper) = self.iter.size_hint();
70
71 (lower / N, upper.map(|n| n / N))
72 }
73
74 #[inline]
75 fn count(self) -> usize {
76 self.iter.count() / N
77 }
78
79 fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
80 where
81 Self: Sized,
82 F: FnMut(B, Self::Item) -> R,
83 R: Try<Output = B>,
84 {
85 let mut acc = init;
86 loop {
87 match self.iter.next_chunk() {
88 Ok(chunk) => acc = f(acc, chunk)?,
89 Err(remainder) => {
90 self.remainder.get_or_insert(remainder);
93
94 break try { acc };
95 }
96 }
97 }
98 }
99
100 fn fold<B, F>(self, init: B, f: F) -> B
101 where
102 Self: Sized,
103 F: FnMut(B, Self::Item) -> B,
104 {
105 <Self as SpecFold>::fold(self, init, f)
106 }
107}
108
109#[unstable(feature = "iter_array_chunks", issue = "100450")]
110impl<I, const N: usize> DoubleEndedIterator for ArrayChunks<I, N>
111where
112 I: DoubleEndedIterator + ExactSizeIterator,
113{
114 #[inline]
115 fn next_back(&mut self) -> Option<Self::Item> {
116 self.try_rfold((), |(), x| ControlFlow::Break(x)).break_value()
117 }
118
119 #[ferrocene::prevalidated]
120 fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
121 where
122 Self: Sized,
123 F: FnMut(B, Self::Item) -> R,
124 R: Try<Output = B>,
125 {
126 self.next_back_remainder();
128
129 let mut acc = init;
130
131 while let Ok(chunk) = self.iter.next_chunk_back() {
135 acc = f(acc, chunk)?
136 }
137
138 try { acc }
139 }
140
141 impl_fold_via_try_fold! { rfold -> try_rfold }
142}
143
144impl<I, const N: usize> ArrayChunks<I, N>
145where
146 I: DoubleEndedIterator + ExactSizeIterator,
147{
148 #[ferrocene::prevalidated]
150 fn next_back_remainder(&mut self) {
151 if self.remainder.is_some() {
154 return;
155 }
156
157 let rem = self.iter.len() % N;
160
161 let mut remainder =
163 unsafe { self.iter.by_ref().rev().take(rem).next_chunk().unwrap_err_unchecked() };
165
166 remainder.as_mut_slice().reverse();
168 self.remainder = Some(remainder);
169 }
170}
171
172#[unstable(feature = "iter_array_chunks", issue = "100450")]
173impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {}
174
175#[unstable(issue = "none", feature = "trusted_fused")]
176unsafe impl<I, const N: usize> TrustedFused for ArrayChunks<I, N> where I: TrustedFused + Iterator {}
177
178#[unstable(feature = "iter_array_chunks", issue = "100450")]
179impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N>
180where
181 I: ExactSizeIterator,
182{
183 #[inline]
184 fn len(&self) -> usize {
185 self.iter.len() / N
186 }
187
188 #[inline]
189 fn is_empty(&self) -> bool {
190 self.iter.len() < N
191 }
192}
193
194trait SpecFold: Iterator {
195 fn fold<B, F>(self, init: B, f: F) -> B
196 where
197 Self: Sized,
198 F: FnMut(B, Self::Item) -> B;
199}
200
201impl<I, const N: usize> SpecFold for ArrayChunks<I, N>
202where
203 I: Iterator,
204{
205 #[inline]
206 default fn fold<B, F>(mut self, init: B, f: F) -> B
207 where
208 Self: Sized,
209 F: FnMut(B, Self::Item) -> B,
210 {
211 self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0
212 }
213}
214
215impl<I, const N: usize> SpecFold for ArrayChunks<I, N>
216where
217 I: Iterator + TrustedRandomAccessNoCoerce,
218{
219 #[inline]
220 fn fold<B, F>(mut self, init: B, mut f: F) -> B
221 where
222 Self: Sized,
223 F: FnMut(B, Self::Item) -> B,
224 {
225 let mut accum = init;
226 let inner_len = self.iter.size();
227 let mut i = 0;
228 while inner_len - i >= N {
230 let chunk = crate::array::from_fn(|local| {
231 unsafe {
234 let idx = i + local;
235 self.iter.__iterator_get_unchecked(idx)
236 }
237 });
238 accum = f(accum, chunk);
239 i += N;
240 }
241
242 accum
246 }
247}
248
249#[unstable(issue = "none", feature = "inplace_iteration")]
250unsafe impl<I, const N: usize> SourceIter for ArrayChunks<I, N>
251where
252 I: SourceIter + Iterator,
253{
254 type Source = I::Source;
255
256 #[inline]
257 unsafe fn as_inner(&mut self) -> &mut I::Source {
258 unsafe { SourceIter::as_inner(&mut self.iter) }
260 }
261}
262
263#[unstable(issue = "none", feature = "inplace_iteration")]
264unsafe impl<I: InPlaceIterable + Iterator, const N: usize> InPlaceIterable for ArrayChunks<I, N> {
265 const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
266 const MERGE_BY: Option<NonZero<usize>> = const {
267 match (I::MERGE_BY, NonZero::new(N)) {
268 (Some(m), Some(n)) => m.checked_mul(n),
269 _ => None,
270 }
271 };
272}