1use crate::cmp;
2use crate::fmt::{self, Debug};
3#[cfg(not(feature = "ferrocene_subset"))]
4use crate::iter::{
5 FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen, UncheckedIterator,
6};
7#[cfg(not(feature = "ferrocene_subset"))]
8use crate::num::NonZero;
9
10#[derive(Clone)]
15#[must_use = "iterators are lazy and do nothing unless consumed"]
16#[stable(feature = "rust1", since = "1.0.0")]
17#[cfg_attr(feature = "ferrocene_subset", expect(dead_code))]
18pub struct Zip<A, B> {
19 a: A,
20 b: B,
21 index: usize,
23 len: usize,
24}
25impl<A: Iterator, B: Iterator> Zip<A, B> {
26 pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
27 ZipImpl::new(a, b)
28 }
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")]
70pub fn zip<A, B>(a: A, b: B) -> Zip<A::IntoIter, B::IntoIter>
71where
72 A: IntoIterator,
73 B: IntoIterator,
74{
75 ZipImpl::new(a.into_iter(), b.into_iter())
76}
77
78#[stable(feature = "rust1", since = "1.0.0")]
79impl<A, B> Iterator for Zip<A, B>
80where
81 A: Iterator,
82 B: Iterator,
83{
84 type Item = (A::Item, B::Item);
85
86 #[inline]
87 fn next(&mut self) -> Option<Self::Item> {
88 ZipImpl::next(self)
89 }
90
91 #[inline]
92 fn size_hint(&self) -> (usize, Option<usize>) {
93 ZipImpl::size_hint(self)
94 }
95
96 #[inline]
97 fn nth(&mut self, n: usize) -> Option<Self::Item> {
98 ZipImpl::nth(self, n)
99 }
100
101 #[inline]
102 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
103 where
104 F: FnMut(Acc, Self::Item) -> Acc,
105 {
106 ZipImpl::fold(self, init, f)
107 }
108
109 #[inline]
110 #[cfg(not(feature = "ferrocene_subset"))]
111 unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
112 where
113 Self: TrustedRandomAccessNoCoerce,
114 {
115 unsafe { ZipImpl::get_unchecked(self, idx) }
118 }
119}
120
121#[stable(feature = "rust1", since = "1.0.0")]
122#[cfg(not(feature = "ferrocene_subset"))]
123impl<A, B> DoubleEndedIterator for Zip<A, B>
124where
125 A: DoubleEndedIterator + ExactSizeIterator,
126 B: DoubleEndedIterator + ExactSizeIterator,
127{
128 #[inline]
129 fn next_back(&mut self) -> Option<(A::Item, B::Item)> {
130 ZipImpl::next_back(self)
131 }
132}
133
134#[doc(hidden)]
136trait ZipImpl<A, B> {
137 type Item;
138 fn new(a: A, b: B) -> Self;
139 fn next(&mut self) -> Option<Self::Item>;
140 fn size_hint(&self) -> (usize, Option<usize>);
141 fn nth(&mut self, n: usize) -> Option<Self::Item>;
142 #[cfg(not(feature = "ferrocene_subset"))]
143 fn next_back(&mut self) -> Option<Self::Item>
144 where
145 A: DoubleEndedIterator + ExactSizeIterator,
146 B: DoubleEndedIterator + ExactSizeIterator;
147 fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
148 where
149 F: FnMut(Acc, Self::Item) -> Acc;
150 #[cfg(not(feature = "ferrocene_subset"))]
152 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
153 where
154 Self: Iterator + TrustedRandomAccessNoCoerce;
155}
156
157macro_rules! zip_impl_general_defaults {
160 () => {
161 default fn new(a: A, b: B) -> Self {
162 Zip {
163 a,
164 b,
165 index: 0, len: 0, }
168 }
169
170 #[inline]
171 default fn next(&mut self) -> Option<(A::Item, B::Item)> {
172 let x = self.a.next()?;
173 let y = self.b.next()?;
174 Some((x, y))
175 }
176
177 #[inline]
178 default fn nth(&mut self, n: usize) -> Option<Self::Item> {
179 self.super_nth(n)
180 }
181
182 #[inline]
183 #[cfg(not(feature = "ferrocene_subset"))]
184 default fn next_back(&mut self) -> Option<(A::Item, B::Item)>
185 where
186 A: DoubleEndedIterator + ExactSizeIterator,
187 B: DoubleEndedIterator + ExactSizeIterator,
188 {
189 let a_sz = self.a.len();
194 let b_sz = self.b.len();
195 if a_sz != b_sz {
196 if a_sz > b_sz {
198 for _ in 0..a_sz - b_sz {
199 self.a.next_back();
200 }
201 } else {
202 for _ in 0..b_sz - a_sz {
203 self.b.next_back();
204 }
205 }
206 }
207 match (self.a.next_back(), self.b.next_back()) {
208 (Some(x), Some(y)) => Some((x, y)),
209 (None, None) => None,
210 _ => unreachable!(),
211 }
212 }
213 };
214}
215
216#[doc(hidden)]
218impl<A, B> ZipImpl<A, B> for Zip<A, B>
219where
220 A: Iterator,
221 B: Iterator,
222{
223 type Item = (A::Item, B::Item);
224
225 zip_impl_general_defaults! {}
226
227 #[inline]
228 default fn size_hint(&self) -> (usize, Option<usize>) {
229 let (a_lower, a_upper) = self.a.size_hint();
230 let (b_lower, b_upper) = self.b.size_hint();
231
232 let lower = cmp::min(a_lower, b_lower);
233
234 let upper = match (a_upper, b_upper) {
235 (Some(x), Some(y)) => Some(cmp::min(x, y)),
236 (Some(x), None) => Some(x),
237 (None, Some(y)) => Some(y),
238 (None, None) => None,
239 };
240
241 (lower, upper)
242 }
243
244 #[cfg(not(feature = "ferrocene_subset"))]
245 default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
246 where
247 Self: TrustedRandomAccessNoCoerce,
248 {
249 unreachable!("Always specialized");
250 }
251
252 #[inline]
253 default fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
254 where
255 F: FnMut(Acc, Self::Item) -> Acc,
256 {
257 SpecFold::spec_fold(self, init, f)
258 }
259}
260
261#[doc(hidden)]
262#[cfg(not(feature = "ferrocene_subset"))]
263impl<A, B> ZipImpl<A, B> for Zip<A, B>
264where
265 A: TrustedRandomAccessNoCoerce + Iterator,
266 B: TrustedRandomAccessNoCoerce + Iterator,
267{
268 zip_impl_general_defaults! {}
269
270 #[inline]
271 default fn size_hint(&self) -> (usize, Option<usize>) {
272 let size = cmp::min(self.a.size(), self.b.size());
273 (size, Some(size))
274 }
275
276 #[inline]
277 unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
278 let idx = self.index + idx;
279 unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) }
282 }
283
284 #[inline]
285 fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
286 where
287 F: FnMut(Acc, Self::Item) -> Acc,
288 {
289 let mut accum = init;
290 let len = ZipImpl::size_hint(&self).0;
291 for i in 0..len {
292 unsafe {
296 accum = f(accum, self.get_unchecked(i));
297 }
298 }
299 accum
300 }
301}
302
303#[doc(hidden)]
304#[cfg(not(feature = "ferrocene_subset"))]
305impl<A, B> ZipImpl<A, B> for Zip<A, B>
306where
307 A: TrustedRandomAccess + Iterator,
308 B: TrustedRandomAccess + Iterator,
309{
310 fn new(a: A, b: B) -> Self {
311 let len = cmp::min(a.size(), b.size());
312 Zip { a, b, index: 0, len }
313 }
314
315 #[inline]
316 fn next(&mut self) -> Option<(A::Item, B::Item)> {
317 if self.index < self.len {
318 let i = self.index;
319 self.index += 1;
322 unsafe {
324 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
325 }
326 } else {
327 None
328 }
329 }
330
331 #[inline]
332 fn size_hint(&self) -> (usize, Option<usize>) {
333 let len = self.len - self.index;
334 (len, Some(len))
335 }
336
337 #[inline]
338 fn nth(&mut self, n: usize) -> Option<Self::Item> {
339 let delta = cmp::min(n, self.len - self.index);
340 let end = self.index + delta;
341 while self.index < end {
342 let i = self.index;
343 self.index += 1;
346 if A::MAY_HAVE_SIDE_EFFECT {
347 unsafe {
351 self.a.__iterator_get_unchecked(i);
352 }
353 }
354 if B::MAY_HAVE_SIDE_EFFECT {
355 unsafe {
357 self.b.__iterator_get_unchecked(i);
358 }
359 }
360 }
361
362 self.super_nth(n - delta)
363 }
364
365 #[inline]
366 fn next_back(&mut self) -> Option<(A::Item, B::Item)>
367 where
368 A: DoubleEndedIterator + ExactSizeIterator,
369 B: DoubleEndedIterator + ExactSizeIterator,
370 {
371 if self.index < self.len {
375 let old_len = self.len;
376
377 self.len -= 1;
382
383 if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
385 let sz_a = self.a.size();
389 let sz_b = self.b.size();
390 if sz_a != sz_b && (old_len == sz_a || old_len == sz_b) {
394 if A::MAY_HAVE_SIDE_EFFECT && sz_a > old_len {
395 for _ in 0..sz_a - old_len {
396 self.a.next_back();
397 }
398 }
399 if B::MAY_HAVE_SIDE_EFFECT && sz_b > old_len {
400 for _ in 0..sz_b - old_len {
401 self.b.next_back();
402 }
403 }
404 debug_assert_eq!(self.a.size(), self.b.size());
405 }
406 }
407 let i = self.len;
408 unsafe {
411 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
412 }
413 } else {
414 None
415 }
416 }
417}
418
419#[stable(feature = "rust1", since = "1.0.0")]
420#[cfg(not(feature = "ferrocene_subset"))]
421impl<A, B> ExactSizeIterator for Zip<A, B>
422where
423 A: ExactSizeIterator,
424 B: ExactSizeIterator,
425{
426}
427
428#[doc(hidden)]
429#[unstable(feature = "trusted_random_access", issue = "none")]
430#[cfg(not(feature = "ferrocene_subset"))]
431unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
432where
433 A: TrustedRandomAccess,
434 B: TrustedRandomAccess,
435{
436}
437
438#[doc(hidden)]
439#[unstable(feature = "trusted_random_access", issue = "none")]
440#[cfg(not(feature = "ferrocene_subset"))]
441unsafe impl<A, B> TrustedRandomAccessNoCoerce for Zip<A, B>
442where
443 A: TrustedRandomAccessNoCoerce,
444 B: TrustedRandomAccessNoCoerce,
445{
446 const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT;
447}
448
449#[stable(feature = "fused", since = "1.26.0")]
450#[cfg(not(feature = "ferrocene_subset"))]
451impl<A, B> FusedIterator for Zip<A, B>
452where
453 A: FusedIterator,
454 B: FusedIterator,
455{
456}
457
458#[unstable(issue = "none", feature = "trusted_fused")]
459#[cfg(not(feature = "ferrocene_subset"))]
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")]
468#[cfg(not(feature = "ferrocene_subset"))]
469unsafe impl<A, B> TrustedLen for Zip<A, B>
470where
471 A: TrustedLen,
472 B: TrustedLen,
473{
474}
475
476#[cfg(not(feature = "ferrocene_subset"))]
477impl<A, B> UncheckedIterator for Zip<A, B>
478where
479 A: UncheckedIterator,
480 B: UncheckedIterator,
481{
482}
483
484#[unstable(issue = "none", feature = "inplace_iteration")]
487#[cfg(not(feature = "ferrocene_subset"))]
488unsafe impl<A, B> SourceIter for Zip<A, B>
489where
490 A: SourceIter,
491{
492 type Source = A::Source;
493
494 #[inline]
495 unsafe fn as_inner(&mut self) -> &mut A::Source {
496 unsafe { SourceIter::as_inner(&mut self.a) }
498 }
499}
500
501#[unstable(issue = "none", feature = "inplace_iteration")]
503#[cfg(not(feature = "ferrocene_subset"))]
504unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> {
505 const EXPAND_BY: Option<NonZero<usize>> = A::EXPAND_BY;
506 const MERGE_BY: Option<NonZero<usize>> = A::MERGE_BY;
507}
508
509#[stable(feature = "rust1", since = "1.0.0")]
510impl<A: Debug, B: Debug> Debug for Zip<A, B> {
511 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512 ZipFmt::fmt(self, f)
513 }
514}
515
516trait ZipFmt<A, B> {
517 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
518}
519
520impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> {
521 default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522 f.debug_struct("Zip").field("a", &self.a).field("b", &self.b).finish()
523 }
524}
525
526impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoerce> ZipFmt<A, B>
527 for Zip<A, B>
528{
529 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
530 f.debug_struct("Zip").finish()
533 }
534}
535
536#[doc(hidden)]
590#[unstable(feature = "trusted_random_access", issue = "none")]
591#[rustc_specialization_trait]
592#[cfg(not(feature = "ferrocene_subset"))]
593pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {}
594
595#[doc(hidden)]
604#[unstable(feature = "trusted_random_access", issue = "none")]
605#[rustc_specialization_trait]
606pub unsafe trait TrustedRandomAccessNoCoerce: Sized {
607 fn size(&self) -> usize
609 where
610 Self: Iterator,
611 {
612 self.size_hint().0
613 }
614 const MAY_HAVE_SIDE_EFFECT: bool;
617}
618
619#[doc(hidden)]
626#[inline]
627#[cfg(not(feature = "ferrocene_subset"))]
628pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
629where
630 I: Iterator,
631{
632 unsafe { it.try_get_unchecked(idx) }
635}
636
637#[cfg(not(feature = "ferrocene_subset"))]
638unsafe trait SpecTrustedRandomAccess: Iterator {
639 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item;
642}
643
644#[cfg(not(feature = "ferrocene_subset"))]
645unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
646 default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item {
647 panic!("Should only be called on TrustedRandomAccess iterators");
648 }
649}
650
651#[cfg(not(feature = "ferrocene_subset"))]
652unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
653 #[inline]
654 unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
655 unsafe { self.__iterator_get_unchecked(index) }
658 }
659}
660
661trait SpecFold: Iterator {
662 fn spec_fold<B, F>(self, init: B, f: F) -> B
663 where
664 Self: Sized,
665 F: FnMut(B, Self::Item) -> B;
666}
667
668impl<A: Iterator, B: Iterator> SpecFold for Zip<A, B> {
669 #[inline]
671 default fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
672 where
673 F: FnMut(Acc, Self::Item) -> Acc,
674 {
675 let mut accum = init;
676 while let Some(x) = ZipImpl::next(&mut self) {
677 accum = f(accum, x);
678 }
679 accum
680 }
681}
682
683#[cfg(not(feature = "ferrocene_subset"))]
684impl<A: TrustedLen, B: TrustedLen> SpecFold for Zip<A, B> {
685 #[inline]
686 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 loop {
692 let (upper, more) = if let Some(upper) = ZipImpl::size_hint(&self).1 {
693 (upper, false)
694 } else {
695 (usize::MAX, true)
697 };
698
699 for _ in 0..upper {
700 let pair =
701 unsafe { (self.a.next().unwrap_unchecked(), self.b.next().unwrap_unchecked()) };
704 accum = f(accum, pair);
705 }
706
707 if !more {
708 break;
709 }
710 }
711 accum
712 }
713}