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