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")]
13pub struct Zip<A, B> {
14 a: A,
15 b: B,
16 index: usize,
18 len: usize,
19}
20impl<A: Iterator, B: Iterator> Zip<A, B> {
21 pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
22 ZipImpl::new(a, b)
23 }
24 fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> {
25 while let Some(x) = Iterator::next(self) {
26 if n == 0 {
27 return Some(x);
28 }
29 n -= 1;
30 }
31 None
32 }
33}
34
35#[stable(feature = "iter_zip", since = "1.59.0")]
65pub fn zip<A, B>(a: A, b: B) -> Zip<A::IntoIter, B::IntoIter>
66where
67 A: IntoIterator,
68 B: IntoIterator,
69{
70 ZipImpl::new(a.into_iter(), b.into_iter())
71}
72
73#[stable(feature = "rust1", since = "1.0.0")]
74impl<A, B> Iterator for Zip<A, B>
75where
76 A: Iterator,
77 B: Iterator,
78{
79 type Item = (A::Item, B::Item);
80
81 #[inline]
82 fn next(&mut self) -> Option<Self::Item> {
83 ZipImpl::next(self)
84 }
85
86 #[inline]
87 fn size_hint(&self) -> (usize, Option<usize>) {
88 ZipImpl::size_hint(self)
89 }
90
91 #[inline]
92 fn nth(&mut self, n: usize) -> Option<Self::Item> {
93 ZipImpl::nth(self, n)
94 }
95
96 #[inline]
97 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
98 where
99 F: FnMut(Acc, Self::Item) -> Acc,
100 {
101 ZipImpl::fold(self, init, f)
102 }
103
104 #[inline]
105 unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
106 where
107 Self: TrustedRandomAccessNoCoerce,
108 {
109 unsafe { ZipImpl::get_unchecked(self, idx) }
112 }
113}
114
115#[stable(feature = "rust1", since = "1.0.0")]
116impl<A, B> DoubleEndedIterator for Zip<A, B>
117where
118 A: DoubleEndedIterator + ExactSizeIterator,
119 B: DoubleEndedIterator + ExactSizeIterator,
120{
121 #[inline]
122 fn next_back(&mut self) -> Option<(A::Item, B::Item)> {
123 ZipImpl::next_back(self)
124 }
125}
126
127trait ZipImpl<A, B> {
129 type Item;
130 fn new(a: A, b: B) -> Self;
131 fn next(&mut self) -> Option<Self::Item>;
132 fn size_hint(&self) -> (usize, Option<usize>);
133 fn nth(&mut self, n: usize) -> Option<Self::Item>;
134 fn next_back(&mut self) -> Option<Self::Item>
135 where
136 A: DoubleEndedIterator + ExactSizeIterator,
137 B: DoubleEndedIterator + ExactSizeIterator;
138 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
139 where
140 F: FnMut(Acc, Self::Item) -> Acc;
141 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
143 where
144 Self: Iterator + TrustedRandomAccessNoCoerce;
145}
146
147macro_rules! zip_impl_general_defaults {
150 () => {
151 default fn new(a: A, b: B) -> Self {
152 Zip {
153 a,
154 b,
155 index: 0, len: 0, }
158 }
159
160 #[inline]
161 default fn next(&mut self) -> Option<(A::Item, B::Item)> {
162 let x = self.a.next()?;
163 let y = self.b.next()?;
164 Some((x, y))
165 }
166
167 #[inline]
168 default fn nth(&mut self, n: usize) -> Option<Self::Item> {
169 self.super_nth(n)
170 }
171
172 #[inline]
173 default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
174 where
175 A: DoubleEndedIterator + ExactSizeIterator,
176 B: DoubleEndedIterator + ExactSizeIterator,
177 {
178 let a_sz = self.a.len();
183 let b_sz = self.b.len();
184 if a_sz != b_sz {
185 if a_sz > b_sz {
187 for _ in 0..a_sz - b_sz {
188 self.a.next_back();
189 }
190 } else {
191 for _ in 0..b_sz - a_sz {
192 self.b.next_back();
193 }
194 }
195 }
196 match (self.a.next_back(), self.b.next_back()) {
197 (Some(x), Some(y)) => Some((x, y)),
198 (None, None) => None,
199 _ => unreachable!(),
200 }
201 }
202 };
203}
204
205impl<A, B> ZipImpl<A, B> for Zip<A, B>
207where
208 A: Iterator,
209 B: Iterator,
210{
211 type Item = (A::Item, B::Item);
212
213 zip_impl_general_defaults! {}
214
215 #[inline]
216 default fn size_hint(&self) -> (usize, Option<usize>) {
217 let (a_lower, a_upper) = self.a.size_hint();
218 let (b_lower, b_upper) = self.b.size_hint();
219
220 let lower = cmp::min(a_lower, b_lower);
221
222 let upper = match (a_upper, b_upper) {
223 (Some(x), Some(y)) => Some(cmp::min(x, y)),
224 (Some(x), None) => Some(x),
225 (None, Some(y)) => Some(y),
226 (None, None) => None,
227 };
228
229 (lower, upper)
230 }
231
232 default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
233 where
234 Self: TrustedRandomAccessNoCoerce,
235 {
236 unreachable!("Always specialized");
237 }
238
239 #[inline]
240 default fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
241 where
242 F: FnMut(Acc, Self::Item) -> Acc,
243 {
244 SpecFold::spec_fold(self, init, f)
245 }
246}
247
248impl<A, B> ZipImpl<A, B> for Zip<A, B>
249where
250 A: TrustedRandomAccessNoCoerce + Iterator,
251 B: TrustedRandomAccessNoCoerce + Iterator,
252{
253 zip_impl_general_defaults! {}
254
255 #[inline]
256 default fn size_hint(&self) -> (usize, Option<usize>) {
257 let size = cmp::min(self.a.size(), self.b.size());
258 (size, Some(size))
259 }
260
261 #[inline]
262 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
263 let idx = self.index + idx;
264 unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
267 }
268
269 #[inline]
270 fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
271 where
272 F: FnMut(Acc, Self::Item) -> Acc,
273 {
274 let mut accum = init;
275 let len = ZipImpl::size_hint(&self).0;
276 for i in 0..len {
277 unsafe {
281 accum = f(accum, self.get_unchecked(i));
282 }
283 }
284 accum
285 }
286}
287
288impl<A, B> ZipImpl<A, B> for Zip<A, B>
289where
290 A: TrustedRandomAccess + Iterator,
291 B: TrustedRandomAccess + Iterator,
292{
293 fn new(a: A, b: B) -> Self {
294 let len = cmp::min(a.size(), b.size());
295 Zip { a, b, index: 0, len }
296 }
297
298 #[inline]
299 fn next(&mut self) -> Option<(A::Item, B::Item)> {
300 if self.index < self.len {
301 let i = self.index;
302 self.index += 1;
305 unsafe {
307 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
308 }
309 } else {
310 None
311 }
312 }
313
314 #[inline]
315 fn size_hint(&self) -> (usize, Option<usize>) {
316 let len = self.len - self.index;
317 (len, Some(len))
318 }
319
320 #[inline]
321 fn nth(&mut self, n: usize) -> Option<Self::Item> {
322 let delta = cmp::min(n, self.len - self.index);
323 let end = self.index + delta;
324 while self.index < end {
325 let i = self.index;
326 self.index += 1;
329 if A::MAY_HAVE_SIDE_EFFECT {
330 unsafe {
334 self.a.__iterator_get_unchecked(i);
335 }
336 }
337 if B::MAY_HAVE_SIDE_EFFECT {
338 unsafe {
340 self.b.__iterator_get_unchecked(i);
341 }
342 }
343 }
344
345 self.super_nth(n - delta)
346 }
347
348 #[inline]
349 fn next_back(&mut self) -> Option<(A::Item, B::Item)>
350 where
351 A: DoubleEndedIterator + ExactSizeIterator,
352 B: DoubleEndedIterator + ExactSizeIterator,
353 {
354 if self.index < self.len {
358 let old_len = self.len;
359
360 self.len -= 1;
365
366 if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
368 let sz_a = self.a.size();
372 let sz_b = self.b.size();
373 if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) {
377 if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len {
378 for _ in 0..sz_a - old_len {
379 self.a.next_back();
380 }
381 }
382 if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len {
383 for _ in 0..sz_b - old_len {
384 self.b.next_back();
385 }
386 }
387 debug_assert_eq!(self.a.size(), self.b.size());
388 }
389 }
390 let i = self.len;
391 unsafe {
394 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
395 }
396 } else {
397 None
398 }
399 }
400}
401
402#[stable(feature = "rust1", since = "1.0.0")]
403impl<A, B> ExactSizeIterator for Zip<A, B>
404where
405 A: ExactSizeIterator,
406 B: ExactSizeIterator,
407{
408}
409
410#[doc(hidden)]
411#[unstable(feature = "trusted_random_access", issue = "none")]
412unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
413where
414 A: TrustedRandomAccess,
415 B: TrustedRandomAccess,
416{
417}
418
419#[doc(hidden)]
420#[unstable(feature = "trusted_random_access", issue = "none")]
421unsafe impl<A, B> TrustedRandomAccessNoCoerce for Zip<A, B>
422where
423 A: TrustedRandomAccessNoCoerce,
424 B: TrustedRandomAccessNoCoerce,
425{
426 const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT;
427}
428
429#[stable(feature = "fused", since = "1.26.0")]
430impl<A, B> FusedIterator for Zip<A, B>
431where
432 A: FusedIterator,
433 B: FusedIterator,
434{
435}
436
437#[unstable(issue = "none", feature = "trusted_fused")]
438unsafe impl<A, B> TrustedFused for Zip<A, B>
439where
440 A: TrustedFused,
441 B: TrustedFused,
442{
443}
444
445#[unstable(feature = "trusted_len", issue = "37572")]
446unsafe impl<A, B> TrustedLen for Zip<A, B>
447where
448 A: TrustedLen,
449 B: TrustedLen,
450{
451}
452
453#[unstable(issue = "none", feature = "inplace_iteration")]
456unsafe impl<A, B> SourceIter for Zip<A, B>
457where
458 A: SourceIter,
459{
460 type Source = A::Source;
461
462 #[inline]
463 unsafe fn as_inner(&mut self) -> &mut A::Source {
464 unsafe { SourceIter::as_inner(&mut self.a) }
466 }
467}
468
469#[unstable(issue = "none", feature = "inplace_iteration")]
471unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> {
472 const EXPAND_BY: Option<NonZero<usize>> = A::EXPAND_BY;
473 const MERGE_BY: Option<NonZero<usize>> = A::MERGE_BY;
474}
475
476#[stable(feature = "rust1", since = "1.0.0")]
477impl<A: Debug, B: Debug> Debug for Zip<A, B> {
478 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479 ZipFmt::fmt(self, f)
480 }
481}
482
483trait ZipFmt<A, B> {
484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
485}
486
487impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> {
488 default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489 f.debug_struct("Zip").field("a", &self.a).field("b", &self.b).finish()
490 }
491}
492
493impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoerce> ZipFmt<A, B>
494 for Zip<A, B>
495{
496 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
497 f.debug_struct("Zip").finish()
500 }
501}
502
503#[doc(hidden)]
557#[unstable(feature = "trusted_random_access", issue = "none")]
558#[rustc_specialization_trait]
559pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {}
560
561#[doc(hidden)]
570#[unstable(feature = "trusted_random_access", issue = "none")]
571#[rustc_specialization_trait]
572pub unsafe trait TrustedRandomAccessNoCoerce: Sized {
573 fn size(&self) -> usize
575 where
576 Self: Iterator,
577 {
578 self.size_hint().0
579 }
580 const MAY_HAVE_SIDE_EFFECT: bool;
583}
584
585#[doc(hidden)]
592#[inline]
593pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
594where
595 I: Iterator,
596{
597 unsafe { it.try_get_unchecked(idx) }
600}
601
602unsafe trait SpecTrustedRandomAccess: Iterator {
603 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item;
606}
607
608unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
609 default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item {
610 panic!("Should only be called on TrustedRandomAccess iterators");
611 }
612}
613
614unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
615 #[inline]
616 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
617 unsafe { self.__iterator_get_unchecked(index) }
620 }
621}
622
623trait SpecFold: Iterator {
624 fn spec_fold<B, F>(self, init: B, f: F) -> B
625 where
626 Self: Sized,
627 F: FnMut(B, Self::Item) -> B;
628}
629
630impl<A: Iterator, B: Iterator> SpecFold for Zip<A, B> {
631 #[inline]
633 default fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
634 where
635 F: FnMut(Acc, Self::Item) -> Acc,
636 {
637 let mut accum = init;
638 while let Some(x) = ZipImpl::next(&mut self) {
639 accum = f(accum, x);
640 }
641 accum
642 }
643}
644
645impl<A: TrustedLen, B: TrustedLen> SpecFold for Zip<A, B> {
646 #[inline]
647 fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
648 where
649 F: FnMut(Acc, Self::Item) -> Acc,
650 {
651 let mut accum = init;
652 loop {
653 let (upper, more) = if let Some(upper) = ZipImpl::size_hint(&self).1 {
654 (upper, false)
655 } else {
656 (usize::MAX, true)
658 };
659
660 for _ in 0..upper {
661 let pair =
662 unsafe { (self.a.next().unwrap_unchecked(), self.b.next().unwrap_unchecked()) };
665 accum = f(accum, pair);
666 }
667
668 if !more {
669 break;
670 }
671 }
672 accum
673 }
674}