1use crate::cmp;
2#[cfg(not(feature = "ferrocene_certified"))]
3use crate::fmt::{self, Debug};
4#[cfg(not(feature = "ferrocene_certified"))]
5use crate::iter::{
6    FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen, UncheckedIterator,
7};
8#[cfg(not(feature = "ferrocene_certified"))]
9use crate::num::NonZero;
10
11#[derive(Clone)]
16#[must_use = "iterators are lazy and do nothing unless consumed"]
17#[stable(feature = "rust1", since = "1.0.0")]
18#[cfg_attr(feature = "ferrocene_certified", expect(dead_code))]
19pub struct Zip<A, B> {
20    a: A,
21    b: B,
22    index: usize,
24    len: usize,
25}
26#[cfg(not(feature = "ferrocene_certified"))]
27impl<A: Iterator, B: Iterator> Zip<A, B> {
28    pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
29        ZipImpl::new(a, b)
30    }
31    fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> {
32        while let Some(x) = Iterator::next(self) {
33            if n == 0 {
34                return Some(x);
35            }
36            n -= 1;
37        }
38        None
39    }
40}
41
42#[stable(feature = "iter_zip", since = "1.59.0")]
72pub fn zip<A, B>(a: A, b: B) -> Zip<A::IntoIter, B::IntoIter>
73where
74    A: IntoIterator,
75    B: IntoIterator,
76{
77    ZipImpl::new(a.into_iter(), b.into_iter())
78}
79
80#[stable(feature = "rust1", since = "1.0.0")]
81impl<A, B> Iterator for Zip<A, B>
82where
83    A: Iterator,
84    B: Iterator,
85{
86    type Item = (A::Item, B::Item);
87
88    #[inline]
89    fn next(&mut self) -> Option<Self::Item> {
90        ZipImpl::next(self)
91    }
92
93    #[inline]
94    fn size_hint(&self) -> (usize, Option<usize>) {
95        ZipImpl::size_hint(self)
96    }
97
98    #[inline]
99    #[cfg(not(feature = "ferrocene_certified"))]
100    fn nth(&mut self, n: usize) -> Option<Self::Item> {
101        ZipImpl::nth(self, n)
102    }
103
104    #[inline]
105    #[cfg(not(feature = "ferrocene_certified"))]
106    fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
107    where
108        F: FnMut(Acc, Self::Item) -> Acc,
109    {
110        ZipImpl::fold(self, init, f)
111    }
112
113    #[inline]
114    #[cfg(not(feature = "ferrocene_certified"))]
115    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
116    where
117        Self: TrustedRandomAccessNoCoerce,
118    {
119        unsafe { ZipImpl::get_unchecked(self, idx) }
122    }
123}
124
125#[stable(feature = "rust1", since = "1.0.0")]
126#[cfg(not(feature = "ferrocene_certified"))]
127impl<A, B> DoubleEndedIterator for Zip<A, B>
128where
129    A: DoubleEndedIterator + ExactSizeIterator,
130    B: DoubleEndedIterator + ExactSizeIterator,
131{
132    #[inline]
133    fn next_back(&mut self) -> Option<(A::Item, B::Item)> {
134        ZipImpl::next_back(self)
135    }
136}
137
138#[doc(hidden)]
140trait ZipImpl<A, B> {
141    type Item;
142    fn new(a: A, b: B) -> Self;
143    fn next(&mut self) -> Option<Self::Item>;
144    fn size_hint(&self) -> (usize, Option<usize>);
145    #[cfg(not(feature = "ferrocene_certified"))]
146    fn nth(&mut self, n: usize) -> Option<Self::Item>;
147    #[cfg(not(feature = "ferrocene_certified"))]
148    fn next_back(&mut self) -> Option<Self::Item>
149    where
150        A: DoubleEndedIterator + ExactSizeIterator,
151        B: DoubleEndedIterator + ExactSizeIterator;
152    #[cfg(not(feature = "ferrocene_certified"))]
153    fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
154    where
155        F: FnMut(Acc, Self::Item) -> Acc;
156    #[cfg(not(feature = "ferrocene_certified"))]
158    unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
159    where
160        Self: Iterator + TrustedRandomAccessNoCoerce;
161}
162
163macro_rules! zip_impl_general_defaults {
166    () => {
167        default fn new(a: A, b: B) -> Self {
168            Zip {
169                a,
170                b,
171                index: 0, len: 0,   }
174        }
175
176        #[inline]
177        default fn next(&mut self) -> Option<(A::Item, B::Item)> {
178            let x = self.a.next()?;
179            let y = self.b.next()?;
180            Some((x, y))
181        }
182
183        #[inline]
184        #[cfg(not(feature = "ferrocene_certified"))]
185        default fn nth(&mut self, n: usize) -> Option<Self::Item> {
186            self.super_nth(n)
187        }
188
189        #[inline]
190        #[cfg(not(feature = "ferrocene_certified"))]
191        default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
192        where
193            A: DoubleEndedIterator + ExactSizeIterator,
194            B: DoubleEndedIterator + ExactSizeIterator,
195        {
196            let a_sz = self.a.len();
201            let b_sz = self.b.len();
202            if a_sz != b_sz {
203                if a_sz > b_sz {
205                    for _ in 0..a_sz - b_sz {
206                        self.a.next_back();
207                    }
208                } else {
209                    for _ in 0..b_sz - a_sz {
210                        self.b.next_back();
211                    }
212                }
213            }
214            match (self.a.next_back(), self.b.next_back()) {
215                (Some(x), Some(y)) => Some((x, y)),
216                (None, None) => None,
217                _ => unreachable!(),
218            }
219        }
220    };
221}
222
223#[doc(hidden)]
225impl<A, B> ZipImpl<A, B> for Zip<A, B>
226where
227    A: Iterator,
228    B: Iterator,
229{
230    type Item = (A::Item, B::Item);
231
232    zip_impl_general_defaults! {}
233
234    #[inline]
235    default fn size_hint(&self) -> (usize, Option<usize>) {
236        let (a_lower, a_upper) = self.a.size_hint();
237        let (b_lower, b_upper) = self.b.size_hint();
238
239        let lower = cmp::min(a_lower, b_lower);
240
241        let upper = match (a_upper, b_upper) {
242            (Some(x), Some(y)) => Some(cmp::min(x, y)),
243            (Some(x), None) => Some(x),
244            (None, Some(y)) => Some(y),
245            (None, None) => None,
246        };
247
248        (lower, upper)
249    }
250
251    #[cfg(not(feature = "ferrocene_certified"))]
252    default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
253    where
254        Self: TrustedRandomAccessNoCoerce,
255    {
256        unreachable!("Always specialized");
257    }
258
259    #[inline]
260    #[cfg(not(feature = "ferrocene_certified"))]
261    default fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
262    where
263        F: FnMut(Acc, Self::Item) -> Acc,
264    {
265        SpecFold::spec_fold(self, init, f)
266    }
267}
268
269#[doc(hidden)]
270#[cfg(not(feature = "ferrocene_certified"))]
271impl<A, B> ZipImpl<A, B> for Zip<A, B>
272where
273    A: TrustedRandomAccessNoCoerce + Iterator,
274    B: TrustedRandomAccessNoCoerce + Iterator,
275{
276    zip_impl_general_defaults! {}
277
278    #[inline]
279    default fn size_hint(&self) -> (usize, Option<usize>) {
280        let size = cmp::min(self.a.size(), self.b.size());
281        (size, Some(size))
282    }
283
284    #[inline]
285    unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
286        let idx = self.index + idx;
287        unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
290    }
291
292    #[inline]
293    fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
294    where
295        F: FnMut(Acc, Self::Item) -> Acc,
296    {
297        let mut accum = init;
298        let len = ZipImpl::size_hint(&self).0;
299        for i in 0..len {
300            unsafe {
304                accum = f(accum, self.get_unchecked(i));
305            }
306        }
307        accum
308    }
309}
310
311#[doc(hidden)]
312#[cfg(not(feature = "ferrocene_certified"))]
313impl<A, B> ZipImpl<A, B> for Zip<A, B>
314where
315    A: TrustedRandomAccess + Iterator,
316    B: TrustedRandomAccess + Iterator,
317{
318    fn new(a: A, b: B) -> Self {
319        let len = cmp::min(a.size(), b.size());
320        Zip { a, b, index: 0, len }
321    }
322
323    #[inline]
324    fn next(&mut self) -> Option<(A::Item, B::Item)> {
325        if self.index < self.len {
326            let i = self.index;
327            self.index += 1;
330            unsafe {
332                Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
333            }
334        } else {
335            None
336        }
337    }
338
339    #[inline]
340    fn size_hint(&self) -> (usize, Option<usize>) {
341        let len = self.len - self.index;
342        (len, Some(len))
343    }
344
345    #[inline]
346    fn nth(&mut self, n: usize) -> Option<Self::Item> {
347        let delta = cmp::min(n, self.len - self.index);
348        let end = self.index + delta;
349        while self.index < end {
350            let i = self.index;
351            self.index += 1;
354            if A::MAY_HAVE_SIDE_EFFECT {
355                unsafe {
359                    self.a.__iterator_get_unchecked(i);
360                }
361            }
362            if B::MAY_HAVE_SIDE_EFFECT {
363                unsafe {
365                    self.b.__iterator_get_unchecked(i);
366                }
367            }
368        }
369
370        self.super_nth(n - delta)
371    }
372
373    #[inline]
374    fn next_back(&mut self) -> Option<(A::Item, B::Item)>
375    where
376        A: DoubleEndedIterator + ExactSizeIterator,
377        B: DoubleEndedIterator + ExactSizeIterator,
378    {
379        if self.index < self.len {
383            let old_len = self.len;
384
385            self.len -= 1;
390
391            if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
393                let sz_a = self.a.size();
397                let sz_b = self.b.size();
398                if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) {
402                    if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len {
403                        for _ in 0..sz_a - old_len {
404                            self.a.next_back();
405                        }
406                    }
407                    if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len {
408                        for _ in 0..sz_b - old_len {
409                            self.b.next_back();
410                        }
411                    }
412                    debug_assert_eq!(self.a.size(), self.b.size());
413                }
414            }
415            let i = self.len;
416            unsafe {
419                Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
420            }
421        } else {
422            None
423        }
424    }
425}
426
427#[stable(feature = "rust1", since = "1.0.0")]
428#[cfg(not(feature = "ferrocene_certified"))]
429impl<A, B> ExactSizeIterator for Zip<A, B>
430where
431    A: ExactSizeIterator,
432    B: ExactSizeIterator,
433{
434}
435
436#[doc(hidden)]
437#[unstable(feature = "trusted_random_access", issue = "none")]
438#[cfg(not(feature = "ferrocene_certified"))]
439unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
440where
441    A: TrustedRandomAccess,
442    B: TrustedRandomAccess,
443{
444}
445
446#[doc(hidden)]
447#[unstable(feature = "trusted_random_access", issue = "none")]
448#[cfg(not(feature = "ferrocene_certified"))]
449unsafe impl<A, B> TrustedRandomAccessNoCoerce for Zip<A, B>
450where
451    A: TrustedRandomAccessNoCoerce,
452    B: TrustedRandomAccessNoCoerce,
453{
454    const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT;
455}
456
457#[stable(feature = "fused", since = "1.26.0")]
458#[cfg(not(feature = "ferrocene_certified"))]
459impl<A, B> FusedIterator for Zip<A, B>
460where
461    A: FusedIterator,
462    B: FusedIterator,
463{
464}
465
466#[unstable(issue = "none", feature = "trusted_fused")]
467#[cfg(not(feature = "ferrocene_certified"))]
468unsafe impl<A, B> TrustedFused for Zip<A, B>
469where
470    A: TrustedFused,
471    B: TrustedFused,
472{
473}
474
475#[unstable(feature = "trusted_len", issue = "37572")]
476#[cfg(not(feature = "ferrocene_certified"))]
477unsafe impl<A, B> TrustedLen for Zip<A, B>
478where
479    A: TrustedLen,
480    B: TrustedLen,
481{
482}
483
484#[cfg(not(feature = "ferrocene_certified"))]
485impl<A, B> UncheckedIterator for Zip<A, B>
486where
487    A: UncheckedIterator,
488    B: UncheckedIterator,
489{
490}
491
492#[unstable(issue = "none", feature = "inplace_iteration")]
495#[cfg(not(feature = "ferrocene_certified"))]
496unsafe impl<A, B> SourceIter for Zip<A, B>
497where
498    A: SourceIter,
499{
500    type Source = A::Source;
501
502    #[inline]
503    unsafe fn as_inner(&mut self) -> &mut A::Source {
504        unsafe { SourceIter::as_inner(&mut self.a) }
506    }
507}
508
509#[unstable(issue = "none", feature = "inplace_iteration")]
511#[cfg(not(feature = "ferrocene_certified"))]
512unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> {
513    const EXPAND_BY: Option<NonZero<usize>> = A::EXPAND_BY;
514    const MERGE_BY: Option<NonZero<usize>> = A::MERGE_BY;
515}
516
517#[stable(feature = "rust1", since = "1.0.0")]
518#[cfg(not(feature = "ferrocene_certified"))]
519impl<A: Debug, B: Debug> Debug for Zip<A, B> {
520    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
521        ZipFmt::fmt(self, f)
522    }
523}
524
525#[cfg(not(feature = "ferrocene_certified"))]
526trait ZipFmt<A, B> {
527    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
528}
529
530#[cfg(not(feature = "ferrocene_certified"))]
531impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> {
532    default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533        f.debug_struct("Zip").field("a", &self.a).field("b", &self.b).finish()
534    }
535}
536
537#[cfg(not(feature = "ferrocene_certified"))]
538impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoerce> ZipFmt<A, B>
539    for Zip<A, B>
540{
541    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542        f.debug_struct("Zip").finish()
545    }
546}
547
548#[doc(hidden)]
602#[unstable(feature = "trusted_random_access", issue = "none")]
603#[rustc_specialization_trait]
604#[cfg(not(feature = "ferrocene_certified"))]
605pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {}
606
607#[doc(hidden)]
616#[unstable(feature = "trusted_random_access", issue = "none")]
617#[rustc_specialization_trait]
618#[cfg(not(feature = "ferrocene_certified"))]
619pub unsafe trait TrustedRandomAccessNoCoerce: Sized {
620    fn size(&self) -> usize
622    where
623        Self: Iterator,
624    {
625        self.size_hint().0
626    }
627    const MAY_HAVE_SIDE_EFFECT: bool;
630}
631
632#[doc(hidden)]
639#[inline]
640#[cfg(not(feature = "ferrocene_certified"))]
641pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
642where
643    I: Iterator,
644{
645    unsafe { it.try_get_unchecked(idx) }
648}
649
650#[cfg(not(feature = "ferrocene_certified"))]
651unsafe trait SpecTrustedRandomAccess: Iterator {
652    unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item;
655}
656
657#[cfg(not(feature = "ferrocene_certified"))]
658unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
659    default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item {
660        panic!("Should only be called on TrustedRandomAccess iterators");
661    }
662}
663
664#[cfg(not(feature = "ferrocene_certified"))]
665unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
666    #[inline]
667    unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
668        unsafe { self.__iterator_get_unchecked(index) }
671    }
672}
673
674#[cfg(not(feature = "ferrocene_certified"))]
675trait SpecFold: Iterator {
676    fn spec_fold<B, F>(self, init: B, f: F) -> B
677    where
678        Self: Sized,
679        F: FnMut(B, Self::Item) -> B;
680}
681
682#[cfg(not(feature = "ferrocene_certified"))]
683impl<A: Iterator, B: Iterator> SpecFold for Zip<A, B> {
684    #[inline]
686    default fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
687    where
688        F: FnMut(Acc, Self::Item) -> Acc,
689    {
690        let mut accum = init;
691        while let Some(x) = ZipImpl::next(&mut self) {
692            accum = f(accum, x);
693        }
694        accum
695    }
696}
697
698#[cfg(not(feature = "ferrocene_certified"))]
699impl<A: TrustedLen, B: TrustedLen> SpecFold for Zip<A, B> {
700    #[inline]
701    fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
702    where
703        F: FnMut(Acc, Self::Item) -> Acc,
704    {
705        let mut accum = init;
706        loop {
707            let (upper, more) = if let Some(upper) = ZipImpl::size_hint(&self).1 {
708                (upper, false)
709            } else {
710                (usize::MAX, true)
712            };
713
714            for _ in 0..upper {
715                let pair =
716                    unsafe { (self.a.next().unwrap_unchecked(), self.b.next().unwrap_unchecked()) };
719                accum = f(accum, pair);
720            }
721
722            if !more {
723                break;
724            }
725        }
726        accum
727    }
728}