1use crate::cmp;
2use crate::fmt::{self, Debug};
3use crate::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen};
4use crate::num::NonZero;
5
6#[derive(Clone)]
11#[must_use = "iterators are lazy and do nothing unless consumed"]
12#[stable(feature = "rust1", since = "1.0.0")]
13#[ferrocene::prevalidated]
14pub struct Zip<A, B> {
15 a: A,
16 b: B,
17 index: usize,
19 len: usize,
20}
21impl<A: Iterator, B: Iterator> Zip<A, B> {
22 #[ferrocene::prevalidated]
23 pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
24 ZipImpl::new(a, b)
25 }
26 #[ferrocene::prevalidated]
27 fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> {
28 while let Some(x) = Iterator::next(self) {
29 if n == 0 {
30 return Some(x);
31 }
32 n -= 1;
33 }
34 None
35 }
36}
37
38#[stable(feature = "iter_zip", since = "1.59.0")]
68#[ferrocene::prevalidated]
69pub fn zip<A, B>(a: A, b: B) -> Zip<A::IntoIter, B::IntoIter>
70where
71 A: IntoIterator,
72 B: IntoIterator,
73{
74 ZipImpl::new(a.into_iter(), b.into_iter())
75}
76
77#[stable(feature = "rust1", since = "1.0.0")]
78impl<A, B> Iterator for Zip<A, B>
79where
80 A: Iterator,
81 B: Iterator,
82{
83 type Item = (A::Item, B::Item);
84
85 #[inline]
86 #[ferrocene::prevalidated]
87 fn next(&mut self) -> Option<Self::Item> {
88 ZipImpl::next(self)
89 }
90
91 #[inline]
92 #[ferrocene::prevalidated]
93 fn size_hint(&self) -> (usize, Option<usize>) {
94 ZipImpl::size_hint(self)
95 }
96
97 #[inline]
98 #[ferrocene::prevalidated]
99 fn nth(&mut self, n: usize) -> Option<Self::Item> {
100 ZipImpl::nth(self, n)
101 }
102
103 #[inline]
104 #[ferrocene::prevalidated]
105 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
106 where
107 F: FnMut(Acc, Self::Item) -> Acc,
108 {
109 ZipImpl::fold(self, init, f)
110 }
111
112 #[inline]
113 #[ferrocene::prevalidated]
114 unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
115 where
116 Self: TrustedRandomAccessNoCoerce,
117 {
118 unsafe { ZipImpl::get_unchecked(self, idx) }
121 }
122}
123
124#[stable(feature = "rust1", since = "1.0.0")]
125impl<A, B> DoubleEndedIterator for Zip<A, B>
126where
127 A: DoubleEndedIterator + ExactSizeIterator,
128 B: DoubleEndedIterator + ExactSizeIterator,
129{
130 #[inline]
131 fn next_back(&mut self) -> Option<(A::Item, B::Item)> {
132 ZipImpl::next_back(self)
133 }
134}
135
136trait ZipImpl<A, B> {
138 type Item;
139 fn new(a: A, b: B) -> Self;
140 fn next(&mut self) -> Option<Self::Item>;
141 fn size_hint(&self) -> (usize, Option<usize>);
142 fn nth(&mut self, n: usize) -> Option<Self::Item>;
143 fn next_back(&mut self) -> Option<Self::Item>
144 where
145 A: DoubleEndedIterator + ExactSizeIterator,
146 B: DoubleEndedIterator + ExactSizeIterator;
147 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
148 where
149 F: FnMut(Acc, Self::Item) -> Acc;
150 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
152 where
153 Self: Iterator + TrustedRandomAccessNoCoerce;
154}
155
156macro_rules! zip_impl_general_defaults {
159 () => {
160 #[ferrocene::prevalidated]
161 default fn new(a: A, b: B) -> Self {
162 Zip {
163 a,
164 b,
165 index: 0, len: 0, }
168 }
169
170 #[inline]
171 #[ferrocene::prevalidated]
172 default fn next(&mut self) -> Option<(A::Item, B::Item)> {
173 let x = self.a.next()?;
174 let y = self.b.next()?;
175 Some((x, y))
176 }
177
178 #[inline]
179 #[ferrocene::prevalidated]
180 default fn nth(&mut self, n: usize) -> Option<Self::Item> {
181 self.super_nth(n)
182 }
183
184 #[inline]
185 default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
186 where
187 A: DoubleEndedIterator + ExactSizeIterator,
188 B: DoubleEndedIterator + ExactSizeIterator,
189 {
190 let a_sz = self.a.len();
195 let b_sz = self.b.len();
196 if a_sz != b_sz {
197 if a_sz > b_sz {
199 for _ in 0..a_sz - b_sz {
200 self.a.next_back();
201 }
202 } else {
203 for _ in 0..b_sz - a_sz {
204 self.b.next_back();
205 }
206 }
207 }
208 match (self.a.next_back(), self.b.next_back()) {
209 (Some(x), Some(y)) => Some((x, y)),
210 (None, None) => None,
211 _ => unreachable!(),
212 }
213 }
214 };
215}
216
217impl<A, B> ZipImpl<A, B> for Zip<A, B>
219where
220 A: Iterator,
221 B: Iterator,
222{
223 type Item = (A::Item, B::Item);
224
225 zip_impl_general_defaults! {}
226
227 #[inline]
228 #[ferrocene::prevalidated]
229 default fn size_hint(&self) -> (usize, Option<usize>) {
230 let (a_lower, a_upper) = self.a.size_hint();
231 let (b_lower, b_upper) = self.b.size_hint();
232
233 let lower = cmp::min(a_lower, b_lower);
234
235 let upper = match (a_upper, b_upper) {
236 (Some(x), Some(y)) => Some(cmp::min(x, y)),
237 (Some(x), None) => Some(x),
238 (None, Some(y)) => Some(y),
239 (None, None) => None,
240 };
241
242 (lower, upper)
243 }
244
245 default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
246 where
247 Self: TrustedRandomAccessNoCoerce,
248 {
249 unreachable!("Always specialized");
250 }
251
252 #[inline]
253 #[ferrocene::prevalidated]
254 default fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
255 where
256 F: FnMut(Acc, Self::Item) -> Acc,
257 {
258 SpecFold::spec_fold(self, init, f)
259 }
260}
261
262impl<A, B> ZipImpl<A, B> for Zip<A, B>
263where
264 A: TrustedRandomAccessNoCoerce + Iterator,
265 B: TrustedRandomAccessNoCoerce + Iterator,
266{
267 zip_impl_general_defaults! {}
268
269 #[inline]
270 default fn size_hint(&self) -> (usize, Option<usize>) {
271 let size = cmp::min(self.a.size(), self.b.size());
272 (size, Some(size))
273 }
274
275 #[inline]
276 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
277 let idx = self.index + idx;
278 unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
281 }
282
283 #[inline]
284 fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
285 where
286 F: FnMut(Acc, Self::Item) -> Acc,
287 {
288 let mut accum = init;
289 let len = ZipImpl::size_hint(&self).0;
290 for i in 0..len {
291 unsafe {
295 accum = f(accum, self.get_unchecked(i));
296 }
297 }
298 accum
299 }
300}
301
302impl<A, B> ZipImpl<A, B> for Zip<A, B>
303where
304 A: TrustedRandomAccess + Iterator,
305 B: TrustedRandomAccess + Iterator,
306{
307 #[ferrocene::prevalidated]
308 fn new(a: A, b: B) -> Self {
309 let len = cmp::min(a.size(), b.size());
310 Zip { a, b, index: 0, len }
311 }
312
313 #[inline]
314 #[ferrocene::prevalidated]
315 fn next(&mut self) -> Option<(A::Item, B::Item)> {
316 if self.index < self.len {
317 let i = self.index;
318 self.index += 1;
321 unsafe {
323 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
324 }
325 } else {
326 None
327 }
328 }
329
330 #[inline]
331 fn size_hint(&self) -> (usize, Option<usize>) {
332 let len = self.len - self.index;
333 (len, Some(len))
334 }
335
336 #[inline]
337 fn nth(&mut self, n: usize) -> Option<Self::Item> {
338 let delta = cmp::min(n, self.len - self.index);
339 let end = self.index + delta;
340 while self.index < end {
341 let i = self.index;
342 self.index += 1;
345 if A::MAY_HAVE_SIDE_EFFECT {
346 unsafe {
350 self.a.__iterator_get_unchecked(i);
351 }
352 }
353 if B::MAY_HAVE_SIDE_EFFECT {
354 unsafe {
356 self.b.__iterator_get_unchecked(i);
357 }
358 }
359 }
360
361 self.super_nth(n - delta)
362 }
363
364 #[inline]
365 fn next_back(&mut self) -> Option<(A::Item, B::Item)>
366 where
367 A: DoubleEndedIterator + ExactSizeIterator,
368 B: DoubleEndedIterator + ExactSizeIterator,
369 {
370 if self.index < self.len {
374 let old_len = self.len;
375
376 self.len -= 1;
381
382 if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
384 let sz_a = self.a.size();
388 let sz_b = self.b.size();
389 if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) {
393 if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len {
394 for _ in 0..sz_a - old_len {
395 self.a.next_back();
396 }
397 }
398 if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len {
399 for _ in 0..sz_b - old_len {
400 self.b.next_back();
401 }
402 }
403 debug_assert_eq!(self.a.size(), self.b.size());
404 }
405 }
406 let i = self.len;
407 unsafe {
410 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
411 }
412 } else {
413 None
414 }
415 }
416}
417
418#[stable(feature = "rust1", since = "1.0.0")]
419impl<A, B> ExactSizeIterator for Zip<A, B>
420where
421 A: ExactSizeIterator,
422 B: ExactSizeIterator,
423{
424}
425
426#[doc(hidden)]
427#[unstable(feature = "trusted_random_access", issue = "none")]
428unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
429where
430 A: TrustedRandomAccess,
431 B: TrustedRandomAccess,
432{
433}
434
435#[doc(hidden)]
436#[unstable(feature = "trusted_random_access", issue = "none")]
437unsafe impl<A, B> TrustedRandomAccessNoCoerce for Zip<A, B>
438where
439 A: TrustedRandomAccessNoCoerce,
440 B: TrustedRandomAccessNoCoerce,
441{
442 const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT;
443}
444
445#[stable(feature = "fused", since = "1.26.0")]
446impl<A, B> FusedIterator for Zip<A, B>
447where
448 A: FusedIterator,
449 B: FusedIterator,
450{
451}
452
453#[unstable(issue = "none", feature = "trusted_fused")]
454unsafe impl<A, B> TrustedFused for Zip<A, B>
455where
456 A: TrustedFused,
457 B: TrustedFused,
458{
459}
460
461#[unstable(feature = "trusted_len", issue = "37572")]
462unsafe impl<A, B> TrustedLen for Zip<A, B>
463where
464 A: TrustedLen,
465 B: TrustedLen,
466{
467}
468
469#[unstable(issue = "none", feature = "inplace_iteration")]
472unsafe impl<A, B> SourceIter for Zip<A, B>
473where
474 A: SourceIter,
475{
476 type Source = A::Source;
477
478 #[inline]
479 unsafe fn as_inner(&mut self) -> &mut A::Source {
480 unsafe { SourceIter::as_inner(&mut self.a) }
482 }
483}
484
485#[unstable(issue = "none", feature = "inplace_iteration")]
487unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> {
488 const EXPAND_BY: Option<NonZero<usize>> = A::EXPAND_BY;
489 const MERGE_BY: Option<NonZero<usize>> = A::MERGE_BY;
490}
491
492#[stable(feature = "rust1", since = "1.0.0")]
493impl<A: Debug, B: Debug> Debug for Zip<A, B> {
494 #[ferrocene::prevalidated]
495 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
496 ZipFmt::fmt(self, f)
497 }
498}
499
500trait ZipFmt<A, B> {
501 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
502}
503
504impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> {
505 #[ferrocene::prevalidated]
506 default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
507 f.debug_struct("Zip").field("a", &self.a).field("b", &self.b).finish()
508 }
509}
510
511impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoerce> ZipFmt<A, B>
512 for Zip<A, B>
513{
514 #[ferrocene::prevalidated]
515 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
516 f.debug_struct("Zip").finish()
519 }
520}
521
522#[doc(hidden)]
576#[unstable(feature = "trusted_random_access", issue = "none")]
577#[rustc_specialization_trait]
578pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {}
579
580#[doc(hidden)]
589#[unstable(feature = "trusted_random_access", issue = "none")]
590#[rustc_specialization_trait]
591pub unsafe trait TrustedRandomAccessNoCoerce: Sized {
592 #[ferrocene::prevalidated]
594 fn size(&self) -> usize
595 where
596 Self: Iterator,
597 {
598 self.size_hint().0
599 }
600 const MAY_HAVE_SIDE_EFFECT: bool;
603}
604
605#[doc(hidden)]
612#[inline]
613pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
614where
615 I: Iterator,
616{
617 unsafe { it.try_get_unchecked(idx) }
620}
621
622unsafe trait SpecTrustedRandomAccess: Iterator {
623 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item;
626}
627
628unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
629 default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item {
630 panic!("Should only be called on TrustedRandomAccess iterators");
631 }
632}
633
634unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
635 #[inline]
636 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
637 unsafe { self.__iterator_get_unchecked(index) }
640 }
641}
642
643trait SpecFold: Iterator {
644 fn spec_fold<B, F>(self, init: B, f: F) -> B
645 where
646 Self: Sized,
647 F: FnMut(B, Self::Item) -> B;
648}
649
650impl<A: Iterator, B: Iterator> SpecFold for Zip<A, B> {
651 #[inline]
653 #[ferrocene::prevalidated]
654 default fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
655 where
656 F: FnMut(Acc, Self::Item) -> Acc,
657 {
658 let mut accum = init;
659 while let Some(x) = ZipImpl::next(&mut self) {
660 accum = f(accum, x);
661 }
662 accum
663 }
664}
665
666impl<A: TrustedLen, B: TrustedLen> SpecFold for Zip<A, B> {
667 #[inline]
668 fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
669 where
670 F: FnMut(Acc, Self::Item) -> Acc,
671 {
672 let mut accum = init;
673 loop {
674 let (upper, more) = if let Some(upper) = ZipImpl::size_hint(&self).1 {
675 (upper, false)
676 } else {
677 (usize::MAX, true)
679 };
680
681 for _ in 0..upper {
682 let pair =
683 unsafe { (self.a.next().unwrap_unchecked(), self.b.next().unwrap_unchecked()) };
686 accum = f(accum, pair);
687 }
688
689 if !more {
690 break;
691 }
692 }
693 accum
694 }
695}