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}
26impl<A: Iterator, B: Iterator> Zip<A, B> {
27 pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
28 ZipImpl::new(a, b)
29 }
30 fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> {
31 while let Some(x) = Iterator::next(self) {
32 if n == 0 {
33 return Some(x);
34 }
35 n -= 1;
36 }
37 None
38 }
39}
40
41#[stable(feature = "iter_zip", since = "1.59.0")]
71pub fn zip<A, B>(a: A, b: B) -> Zip<A::IntoIter, B::IntoIter>
72where
73 A: IntoIterator,
74 B: IntoIterator,
75{
76 ZipImpl::new(a.into_iter(), b.into_iter())
77}
78
79#[stable(feature = "rust1", since = "1.0.0")]
80impl<A, B> Iterator for Zip<A, B>
81where
82 A: Iterator,
83 B: Iterator,
84{
85 type Item = (A::Item, B::Item);
86
87 #[inline]
88 fn next(&mut self) -> Option<Self::Item> {
89 ZipImpl::next(self)
90 }
91
92 #[inline]
93 fn size_hint(&self) -> (usize, Option<usize>) {
94 ZipImpl::size_hint(self)
95 }
96
97 #[inline]
98 fn nth(&mut self, n: usize) -> Option<Self::Item> {
99 ZipImpl::nth(self, n)
100 }
101
102 #[inline]
103 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
104 where
105 F: FnMut(Acc, Self::Item) -> Acc,
106 {
107 ZipImpl::fold(self, init, f)
108 }
109
110 #[inline]
111 #[cfg(not(feature = "ferrocene_certified"))]
112 unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
113 where
114 Self: TrustedRandomAccessNoCoerce,
115 {
116 unsafe { ZipImpl::get_unchecked(self, idx) }
119 }
120}
121
122#[stable(feature = "rust1", since = "1.0.0")]
123#[cfg(not(feature = "ferrocene_certified"))]
124impl<A, B> DoubleEndedIterator for Zip<A, B>
125where
126 A: DoubleEndedIterator + ExactSizeIterator,
127 B: DoubleEndedIterator + ExactSizeIterator,
128{
129 #[inline]
130 fn next_back(&mut self) -> Option<(A::Item, B::Item)> {
131 ZipImpl::next_back(self)
132 }
133}
134
135#[doc(hidden)]
137trait 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 #[cfg(not(feature = "ferrocene_certified"))]
144 fn next_back(&mut self) -> Option<Self::Item>
145 where
146 A: DoubleEndedIterator + ExactSizeIterator,
147 B: DoubleEndedIterator + ExactSizeIterator;
148 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
149 where
150 F: FnMut(Acc, Self::Item) -> Acc;
151 #[cfg(not(feature = "ferrocene_certified"))]
153 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
154 where
155 Self: Iterator + TrustedRandomAccessNoCoerce;
156}
157
158macro_rules! zip_impl_general_defaults {
161 () => {
162 default fn new(a: A, b: B) -> Self {
163 Zip {
164 a,
165 b,
166 index: 0, len: 0, }
169 }
170
171 #[inline]
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 default fn nth(&mut self, n: usize) -> Option<Self::Item> {
180 self.super_nth(n)
181 }
182
183 #[inline]
184 #[cfg(not(feature = "ferrocene_certified"))]
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
217#[doc(hidden)]
219impl<A, B> ZipImpl<A, B> for Zip<A, B>
220where
221 A: Iterator,
222 B: Iterator,
223{
224 type Item = (A::Item, B::Item);
225
226 zip_impl_general_defaults! {}
227
228 #[inline]
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 #[cfg(not(feature = "ferrocene_certified"))]
246 default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
247 where
248 Self: TrustedRandomAccessNoCoerce,
249 {
250 unreachable!("Always specialized");
251 }
252
253 #[inline]
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
262#[doc(hidden)]
263#[cfg(not(feature = "ferrocene_certified"))]
264impl<A, B> ZipImpl<A, B> for Zip<A, B>
265where
266 A: TrustedRandomAccessNoCoerce + Iterator,
267 B: TrustedRandomAccessNoCoerce + Iterator,
268{
269 zip_impl_general_defaults! {}
270
271 #[inline]
272 default fn size_hint(&self) -> (usize, Option<usize>) {
273 let size = cmp::min(self.a.size(), self.b.size());
274 (size, Some(size))
275 }
276
277 #[inline]
278 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
279 let idx = self.index + idx;
280 unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
283 }
284
285 #[inline]
286 fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
287 where
288 F: FnMut(Acc, Self::Item) -> Acc,
289 {
290 let mut accum = init;
291 let len = ZipImpl::size_hint(&self).0;
292 for i in 0..len {
293 unsafe {
297 accum = f(accum, self.get_unchecked(i));
298 }
299 }
300 accum
301 }
302}
303
304#[doc(hidden)]
305#[cfg(not(feature = "ferrocene_certified"))]
306impl<A, B> ZipImpl<A, B> for Zip<A, B>
307where
308 A: TrustedRandomAccess + Iterator,
309 B: TrustedRandomAccess + Iterator,
310{
311 fn new(a: A, b: B) -> Self {
312 let len = cmp::min(a.size(), b.size());
313 Zip { a, b, index: 0, len }
314 }
315
316 #[inline]
317 fn next(&mut self) -> Option<(A::Item, B::Item)> {
318 if self.index < self.len {
319 let i = self.index;
320 self.index += 1;
323 unsafe {
325 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
326 }
327 } else {
328 None
329 }
330 }
331
332 #[inline]
333 fn size_hint(&self) -> (usize, Option<usize>) {
334 let len = self.len - self.index;
335 (len, Some(len))
336 }
337
338 #[inline]
339 fn nth(&mut self, n: usize) -> Option<Self::Item> {
340 let delta = cmp::min(n, self.len - self.index);
341 let end = self.index + delta;
342 while self.index < end {
343 let i = self.index;
344 self.index += 1;
347 if A::MAY_HAVE_SIDE_EFFECT {
348 unsafe {
352 self.a.__iterator_get_unchecked(i);
353 }
354 }
355 if B::MAY_HAVE_SIDE_EFFECT {
356 unsafe {
358 self.b.__iterator_get_unchecked(i);
359 }
360 }
361 }
362
363 self.super_nth(n - delta)
364 }
365
366 #[inline]
367 fn next_back(&mut self) -> Option<(A::Item, B::Item)>
368 where
369 A: DoubleEndedIterator + ExactSizeIterator,
370 B: DoubleEndedIterator + ExactSizeIterator,
371 {
372 if self.index < self.len {
376 let old_len = self.len;
377
378 self.len -= 1;
383
384 if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
386 let sz_a = self.a.size();
390 let sz_b = self.b.size();
391 if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) {
395 if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len {
396 for _ in 0..sz_a - old_len {
397 self.a.next_back();
398 }
399 }
400 if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len {
401 for _ in 0..sz_b - old_len {
402 self.b.next_back();
403 }
404 }
405 debug_assert_eq!(self.a.size(), self.b.size());
406 }
407 }
408 let i = self.len;
409 unsafe {
412 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
413 }
414 } else {
415 None
416 }
417 }
418}
419
420#[stable(feature = "rust1", since = "1.0.0")]
421#[cfg(not(feature = "ferrocene_certified"))]
422impl<A, B> ExactSizeIterator for Zip<A, B>
423where
424 A: ExactSizeIterator,
425 B: ExactSizeIterator,
426{
427}
428
429#[doc(hidden)]
430#[unstable(feature = "trusted_random_access", issue = "none")]
431#[cfg(not(feature = "ferrocene_certified"))]
432unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
433where
434 A: TrustedRandomAccess,
435 B: TrustedRandomAccess,
436{
437}
438
439#[doc(hidden)]
440#[unstable(feature = "trusted_random_access", issue = "none")]
441#[cfg(not(feature = "ferrocene_certified"))]
442unsafe impl<A, B> TrustedRandomAccessNoCoerce for Zip<A, B>
443where
444 A: TrustedRandomAccessNoCoerce,
445 B: TrustedRandomAccessNoCoerce,
446{
447 const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT;
448}
449
450#[stable(feature = "fused", since = "1.26.0")]
451#[cfg(not(feature = "ferrocene_certified"))]
452impl<A, B> FusedIterator for Zip<A, B>
453where
454 A: FusedIterator,
455 B: FusedIterator,
456{
457}
458
459#[unstable(issue = "none", feature = "trusted_fused")]
460#[cfg(not(feature = "ferrocene_certified"))]
461unsafe impl<A, B> TrustedFused for Zip<A, B>
462where
463 A: TrustedFused,
464 B: TrustedFused,
465{
466}
467
468#[unstable(feature = "trusted_len", issue = "37572")]
469#[cfg(not(feature = "ferrocene_certified"))]
470unsafe impl<A, B> TrustedLen for Zip<A, B>
471where
472 A: TrustedLen,
473 B: TrustedLen,
474{
475}
476
477#[cfg(not(feature = "ferrocene_certified"))]
478impl<A, B> UncheckedIterator for Zip<A, B>
479where
480 A: UncheckedIterator,
481 B: UncheckedIterator,
482{
483}
484
485#[unstable(issue = "none", feature = "inplace_iteration")]
488#[cfg(not(feature = "ferrocene_certified"))]
489unsafe impl<A, B> SourceIter for Zip<A, B>
490where
491 A: SourceIter,
492{
493 type Source = A::Source;
494
495 #[inline]
496 unsafe fn as_inner(&mut self) -> &mut A::Source {
497 unsafe { SourceIter::as_inner(&mut self.a) }
499 }
500}
501
502#[unstable(issue = "none", feature = "inplace_iteration")]
504#[cfg(not(feature = "ferrocene_certified"))]
505unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> {
506 const EXPAND_BY: Option<NonZero<usize>> = A::EXPAND_BY;
507 const MERGE_BY: Option<NonZero<usize>> = A::MERGE_BY;
508}
509
510#[stable(feature = "rust1", since = "1.0.0")]
511#[cfg(not(feature = "ferrocene_certified"))]
512impl<A: Debug, B: Debug> Debug for Zip<A, B> {
513 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
514 ZipFmt::fmt(self, f)
515 }
516}
517
518#[cfg(not(feature = "ferrocene_certified"))]
519trait ZipFmt<A, B> {
520 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
521}
522
523#[cfg(not(feature = "ferrocene_certified"))]
524impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> {
525 default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526 f.debug_struct("Zip").field("a", &self.a).field("b", &self.b).finish()
527 }
528}
529
530#[cfg(not(feature = "ferrocene_certified"))]
531impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoerce> ZipFmt<A, B>
532 for Zip<A, B>
533{
534 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535 f.debug_struct("Zip").finish()
538 }
539}
540
541#[doc(hidden)]
595#[unstable(feature = "trusted_random_access", issue = "none")]
596#[rustc_specialization_trait]
597#[cfg(not(feature = "ferrocene_certified"))]
598pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {}
599
600#[doc(hidden)]
609#[unstable(feature = "trusted_random_access", issue = "none")]
610#[rustc_specialization_trait]
611#[cfg(not(feature = "ferrocene_certified"))]
612pub unsafe trait TrustedRandomAccessNoCoerce: Sized {
613 fn size(&self) -> usize
615 where
616 Self: Iterator,
617 {
618 self.size_hint().0
619 }
620 const MAY_HAVE_SIDE_EFFECT: bool;
623}
624
625#[doc(hidden)]
632#[inline]
633#[cfg(not(feature = "ferrocene_certified"))]
634pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
635where
636 I: Iterator,
637{
638 unsafe { it.try_get_unchecked(idx) }
641}
642
643#[cfg(not(feature = "ferrocene_certified"))]
644unsafe trait SpecTrustedRandomAccess: Iterator {
645 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item;
648}
649
650#[cfg(not(feature = "ferrocene_certified"))]
651unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
652 default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item {
653 panic!("Should only be called on TrustedRandomAccess iterators");
654 }
655}
656
657#[cfg(not(feature = "ferrocene_certified"))]
658unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
659 #[inline]
660 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
661 unsafe { self.__iterator_get_unchecked(index) }
664 }
665}
666
667trait SpecFold: Iterator {
668 fn spec_fold<B, F>(self, init: B, f: F) -> B
669 where
670 Self: Sized,
671 F: FnMut(B, Self::Item) -> B;
672}
673
674impl<A: Iterator, B: Iterator> SpecFold for Zip<A, B> {
675 #[inline]
677 default fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
678 where
679 F: FnMut(Acc, Self::Item) -> Acc,
680 {
681 let mut accum = init;
682 while let Some(x) = ZipImpl::next(&mut self) {
683 accum = f(accum, x);
684 }
685 accum
686 }
687}
688
689#[cfg(not(feature = "ferrocene_certified"))]
690impl<A: TrustedLen, B: TrustedLen> SpecFold for Zip<A, B> {
691 #[inline]
692 fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
693 where
694 F: FnMut(Acc, Self::Item) -> Acc,
695 {
696 let mut accum = init;
697 loop {
698 let (upper, more) = if let Some(upper) = ZipImpl::size_hint(&self).1 {
699 (upper, false)
700 } else {
701 (usize::MAX, true)
703 };
704
705 for _ in 0..upper {
706 let pair =
707 unsafe { (self.a.next().unwrap_unchecked(), self.b.next().unwrap_unchecked()) };
710 accum = f(accum, pair);
711 }
712
713 if !more {
714 break;
715 }
716 }
717 accum
718 }
719}