1use crate::cmp;
2use crate::fmt::{self, Debug};
3use crate::iter::{
4 FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen, UncheckedIterator,
5};
6use crate::num::NonZero;
7
8#[derive(Clone)]
13#[must_use = "iterators are lazy and do nothing unless consumed"]
14#[stable(feature = "rust1", since = "1.0.0")]
15#[ferrocene::prevalidated]
16pub struct Zip<A, B> {
17 a: A,
18 b: B,
19 index: usize,
21 len: usize,
22}
23impl<A: Iterator, B: Iterator> Zip<A, B> {
24 #[ferrocene::prevalidated]
25 pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
26 ZipImpl::new(a, b)
27 }
28 #[ferrocene::prevalidated]
29 fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> {
30 while let Some(x) = Iterator::next(self) {
31 if n == 0 {
32 return Some(x);
33 }
34 n -= 1;
35 }
36 None
37 }
38}
39
40#[stable(feature = "iter_zip", since = "1.59.0")]
70#[ferrocene::prevalidated]
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 #[ferrocene::prevalidated]
89 fn next(&mut self) -> Option<Self::Item> {
90 ZipImpl::next(self)
91 }
92
93 #[inline]
94 #[ferrocene::prevalidated]
95 fn size_hint(&self) -> (usize, Option<usize>) {
96 ZipImpl::size_hint(self)
97 }
98
99 #[inline]
100 #[ferrocene::prevalidated]
101 fn nth(&mut self, n: usize) -> Option<Self::Item> {
102 ZipImpl::nth(self, n)
103 }
104
105 #[inline]
106 #[ferrocene::prevalidated]
107 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
108 where
109 F: FnMut(Acc, Self::Item) -> Acc,
110 {
111 ZipImpl::fold(self, init, f)
112 }
113
114 #[inline]
115 #[ferrocene::prevalidated]
116 unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
117 where
118 Self: TrustedRandomAccessNoCoerce,
119 {
120 unsafe { ZipImpl::get_unchecked(self, idx) }
123 }
124}
125
126#[stable(feature = "rust1", since = "1.0.0")]
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 fn nth(&mut self, n: usize) -> Option<Self::Item>;
146 fn next_back(&mut self) -> Option<Self::Item>
147 where
148 A: DoubleEndedIterator + ExactSizeIterator,
149 B: DoubleEndedIterator + ExactSizeIterator;
150 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
151 where
152 F: FnMut(Acc, Self::Item) -> Acc;
153 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
155 where
156 Self: Iterator + TrustedRandomAccessNoCoerce;
157}
158
159macro_rules! zip_impl_general_defaults {
162 () => {
163 #[ferrocene::prevalidated]
164 default fn new(a: A, b: B) -> Self {
165 Zip {
166 a,
167 b,
168 index: 0, len: 0, }
171 }
172
173 #[inline]
174 #[ferrocene::prevalidated]
175 default fn next(&mut self) -> Option<(A::Item, B::Item)> {
176 let x = self.a.next()?;
177 let y = self.b.next()?;
178 Some((x, y))
179 }
180
181 #[inline]
182 #[ferrocene::prevalidated]
183 default fn nth(&mut self, n: usize) -> Option<Self::Item> {
184 self.super_nth(n)
185 }
186
187 #[inline]
188 default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
189 where
190 A: DoubleEndedIterator + ExactSizeIterator,
191 B: DoubleEndedIterator + ExactSizeIterator,
192 {
193 let a_sz = self.a.len();
198 let b_sz = self.b.len();
199 if a_sz != b_sz {
200 if a_sz > b_sz {
202 for _ in 0..a_sz - b_sz {
203 self.a.next_back();
204 }
205 } else {
206 for _ in 0..b_sz - a_sz {
207 self.b.next_back();
208 }
209 }
210 }
211 match (self.a.next_back(), self.b.next_back()) {
212 (Some(x), Some(y)) => Some((x, y)),
213 (None, None) => None,
214 _ => unreachable!(),
215 }
216 }
217 };
218}
219
220#[doc(hidden)]
222impl<A, B> ZipImpl<A, B> for Zip<A, B>
223where
224 A: Iterator,
225 B: Iterator,
226{
227 type Item = (A::Item, B::Item);
228
229 zip_impl_general_defaults! {}
230
231 #[inline]
232 #[ferrocene::prevalidated]
233 default fn size_hint(&self) -> (usize, Option<usize>) {
234 let (a_lower, a_upper) = self.a.size_hint();
235 let (b_lower, b_upper) = self.b.size_hint();
236
237 let lower = cmp::min(a_lower, b_lower);
238
239 let upper = match (a_upper, b_upper) {
240 (Some(x), Some(y)) => Some(cmp::min(x, y)),
241 (Some(x), None) => Some(x),
242 (None, Some(y)) => Some(y),
243 (None, None) => None,
244 };
245
246 (lower, upper)
247 }
248
249 default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
250 where
251 Self: TrustedRandomAccessNoCoerce,
252 {
253 unreachable!("Always specialized");
254 }
255
256 #[inline]
257 #[ferrocene::prevalidated]
258 default fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
259 where
260 F: FnMut(Acc, Self::Item) -> Acc,
261 {
262 SpecFold::spec_fold(self, init, f)
263 }
264}
265
266#[doc(hidden)]
267impl<A, B> ZipImpl<A, B> for Zip<A, B>
268where
269 A: TrustedRandomAccessNoCoerce + Iterator,
270 B: TrustedRandomAccessNoCoerce + Iterator,
271{
272 zip_impl_general_defaults! {}
273
274 #[inline]
275 default fn size_hint(&self) -> (usize, Option<usize>) {
276 let size = cmp::min(self.a.size(), self.b.size());
277 (size, Some(size))
278 }
279
280 #[inline]
281 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
282 let idx = self.index + idx;
283 unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
286 }
287
288 #[inline]
289 fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
290 where
291 F: FnMut(Acc, Self::Item) -> Acc,
292 {
293 let mut accum = init;
294 let len = ZipImpl::size_hint(&self).0;
295 for i in 0..len {
296 unsafe {
300 accum = f(accum, self.get_unchecked(i));
301 }
302 }
303 accum
304 }
305}
306
307#[doc(hidden)]
308impl<A, B> ZipImpl<A, B> for Zip<A, B>
309where
310 A: TrustedRandomAccess + Iterator,
311 B: TrustedRandomAccess + Iterator,
312{
313 #[ferrocene::prevalidated]
314 fn new(a: A, b: B) -> Self {
315 let len = cmp::min(a.size(), b.size());
316 Zip { a, b, index: 0, len }
317 }
318
319 #[inline]
320 #[ferrocene::prevalidated]
321 fn next(&mut self) -> Option<(A::Item, B::Item)> {
322 if self.index < self.len {
323 let i = self.index;
324 self.index += 1;
327 unsafe {
329 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
330 }
331 } else {
332 None
333 }
334 }
335
336 #[inline]
337 fn size_hint(&self) -> (usize, Option<usize>) {
338 let len = self.len - self.index;
339 (len, Some(len))
340 }
341
342 #[inline]
343 fn nth(&mut self, n: usize) -> Option<Self::Item> {
344 let delta = cmp::min(n, self.len - self.index);
345 let end = self.index + delta;
346 while self.index < end {
347 let i = self.index;
348 self.index += 1;
351 if A::MAY_HAVE_SIDE_EFFECT {
352 unsafe {
356 self.a.__iterator_get_unchecked(i);
357 }
358 }
359 if B::MAY_HAVE_SIDE_EFFECT {
360 unsafe {
362 self.b.__iterator_get_unchecked(i);
363 }
364 }
365 }
366
367 self.super_nth(n - delta)
368 }
369
370 #[inline]
371 fn next_back(&mut self) -> Option<(A::Item, B::Item)>
372 where
373 A: DoubleEndedIterator + ExactSizeIterator,
374 B: DoubleEndedIterator + ExactSizeIterator,
375 {
376 if self.index < self.len {
380 let old_len = self.len;
381
382 self.len -= 1;
387
388 if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
390 let sz_a = self.a.size();
394 let sz_b = self.b.size();
395 if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) {
399 if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len {
400 for _ in 0..sz_a - old_len {
401 self.a.next_back();
402 }
403 }
404 if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len {
405 for _ in 0..sz_b - old_len {
406 self.b.next_back();
407 }
408 }
409 debug_assert_eq!(self.a.size(), self.b.size());
410 }
411 }
412 let i = self.len;
413 unsafe {
416 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
417 }
418 } else {
419 None
420 }
421 }
422}
423
424#[stable(feature = "rust1", since = "1.0.0")]
425impl<A, B> ExactSizeIterator for Zip<A, B>
426where
427 A: ExactSizeIterator,
428 B: ExactSizeIterator,
429{
430}
431
432#[doc(hidden)]
433#[unstable(feature = "trusted_random_access", issue = "none")]
434unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
435where
436 A: TrustedRandomAccess,
437 B: TrustedRandomAccess,
438{
439}
440
441#[doc(hidden)]
442#[unstable(feature = "trusted_random_access", issue = "none")]
443unsafe impl<A, B> TrustedRandomAccessNoCoerce for Zip<A, B>
444where
445 A: TrustedRandomAccessNoCoerce,
446 B: TrustedRandomAccessNoCoerce,
447{
448 const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT;
449}
450
451#[stable(feature = "fused", since = "1.26.0")]
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")]
460unsafe impl<A, B> TrustedFused for Zip<A, B>
461where
462 A: TrustedFused,
463 B: TrustedFused,
464{
465}
466
467#[unstable(feature = "trusted_len", issue = "37572")]
468unsafe impl<A, B> TrustedLen for Zip<A, B>
469where
470 A: TrustedLen,
471 B: TrustedLen,
472{
473}
474
475impl<A, B> UncheckedIterator for Zip<A, B>
476where
477 A: UncheckedIterator,
478 B: UncheckedIterator,
479{
480}
481
482#[unstable(issue = "none", feature = "inplace_iteration")]
485unsafe impl<A, B> SourceIter for Zip<A, B>
486where
487 A: SourceIter,
488{
489 type Source = A::Source;
490
491 #[inline]
492 unsafe fn as_inner(&mut self) -> &mut A::Source {
493 unsafe { SourceIter::as_inner(&mut self.a) }
495 }
496}
497
498#[unstable(issue = "none", feature = "inplace_iteration")]
500unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> {
501 const EXPAND_BY: Option<NonZero<usize>> = A::EXPAND_BY;
502 const MERGE_BY: Option<NonZero<usize>> = A::MERGE_BY;
503}
504
505#[stable(feature = "rust1", since = "1.0.0")]
506impl<A: Debug, B: Debug> Debug for Zip<A, B> {
507 #[ferrocene::prevalidated]
508 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509 ZipFmt::fmt(self, f)
510 }
511}
512
513trait ZipFmt<A, B> {
514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
515}
516
517impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> {
518 #[ferrocene::prevalidated]
519 default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
520 f.debug_struct("Zip").field("a", &self.a).field("b", &self.b).finish()
521 }
522}
523
524impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoerce> ZipFmt<A, B>
525 for Zip<A, B>
526{
527 #[ferrocene::prevalidated]
528 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529 f.debug_struct("Zip").finish()
532 }
533}
534
535#[doc(hidden)]
589#[unstable(feature = "trusted_random_access", issue = "none")]
590#[rustc_specialization_trait]
591pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {}
592
593#[doc(hidden)]
602#[unstable(feature = "trusted_random_access", issue = "none")]
603#[rustc_specialization_trait]
604pub unsafe trait TrustedRandomAccessNoCoerce: Sized {
605 #[ferrocene::prevalidated]
607 fn size(&self) -> usize
608 where
609 Self: Iterator,
610 {
611 self.size_hint().0
612 }
613 const MAY_HAVE_SIDE_EFFECT: bool;
616}
617
618#[doc(hidden)]
625#[inline]
626pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
627where
628 I: Iterator,
629{
630 unsafe { it.try_get_unchecked(idx) }
633}
634
635unsafe trait SpecTrustedRandomAccess: Iterator {
636 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item;
639}
640
641unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
642 default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item {
643 panic!("Should only be called on TrustedRandomAccess iterators");
644 }
645}
646
647unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
648 #[inline]
649 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
650 unsafe { self.__iterator_get_unchecked(index) }
653 }
654}
655
656trait SpecFold: Iterator {
657 fn spec_fold<B, F>(self, init: B, f: F) -> B
658 where
659 Self: Sized,
660 F: FnMut(B, Self::Item) -> B;
661}
662
663impl<A: Iterator, B: Iterator> SpecFold for Zip<A, B> {
664 #[inline]
666 #[ferrocene::prevalidated]
667 default fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
668 where
669 F: FnMut(Acc, Self::Item) -> Acc,
670 {
671 let mut accum = init;
672 while let Some(x) = ZipImpl::next(&mut self) {
673 accum = f(accum, x);
674 }
675 accum
676 }
677}
678
679impl<A: TrustedLen, B: TrustedLen> SpecFold for Zip<A, B> {
680 #[inline]
681 fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
682 where
683 F: FnMut(Acc, Self::Item) -> Acc,
684 {
685 let mut accum = init;
686 loop {
687 let (upper, more) = if let Some(upper) = ZipImpl::size_hint(&self).1 {
688 (upper, false)
689 } else {
690 (usize::MAX, true)
692 };
693
694 for _ in 0..upper {
695 let pair =
696 unsafe { (self.a.next().unwrap_unchecked(), self.b.next().unwrap_unchecked()) };
699 accum = f(accum, pair);
700 }
701
702 if !more {
703 break;
704 }
705 }
706 accum
707 }
708}