1 use super::size_hint;
2 
3 /// See [`multizip`](../fn.multizip.html) for more information.
4 #[derive(Clone, Debug)]
5 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
6 pub struct Zip<T> {
7     t: T,
8 }
9 
10 /// An iterator that generalizes *.zip()* and allows running multiple iterators in lockstep.
11 ///
12 /// The iterator `Zip<(I, J, ..., M)>` is formed from a tuple of iterators (or values that
13 /// implement `IntoIterator`) and yields elements
14 /// until any of the subiterators yields `None`.
15 ///
16 /// The iterator element type is a tuple like like `(A, B, ..., E)` where `A` to `E` are the
17 /// element types of the subiterator.
18 ///
19 /// **Note:** The result of this macro is a value of a named type (`Zip<(I, J,
20 /// ..)>` of each component iterator `I, J, ...`) if each component iterator is
21 /// nameable.
22 ///
23 /// Prefer [`izip!()`] over `multizip` for the performance benefits of using the
24 /// standard library `.zip()`. Prefer `multizip` if a nameable type is needed.
25 ///
26 /// [`izip!()`]: macro.izip.html
27 ///
28 /// ```
29 /// use itertools::multizip;
30 ///
31 /// // iterate over three sequences side-by-side
32 /// let mut results = [0, 0, 0, 0];
33 /// let inputs = [3, 7, 9, 6];
34 ///
35 /// for (r, index, input) in multizip((&mut results, 0..10, &inputs)) {
36 ///     *r = index * 10 + input;
37 /// }
38 ///
39 /// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]);
40 /// ```
multizip<T, U>(t: U) -> Zip<T> where Zip<T>: From<U>, Zip<T>: Iterator,41 pub fn multizip<T, U>(t: U) -> Zip<T>
42     where Zip<T>: From<U>,
43           Zip<T>: Iterator,
44 {
45     Zip::from(t)
46 }
47 
48 macro_rules! impl_zip_iter {
49     ($($B:ident),*) => (
50         #[allow(non_snake_case)]
51         impl<$($B: IntoIterator),*> From<($($B,)*)> for Zip<($($B::IntoIter,)*)> {
52             fn from(t: ($($B,)*)) -> Self {
53                 let ($($B,)*) = t;
54                 Zip { t: ($($B.into_iter(),)*) }
55             }
56         }
57 
58         #[allow(non_snake_case)]
59         #[allow(unused_assignments)]
60         impl<$($B),*> Iterator for Zip<($($B,)*)>
61             where
62             $(
63                 $B: Iterator,
64             )*
65         {
66             type Item = ($($B::Item,)*);
67 
68             fn next(&mut self) -> Option<Self::Item>
69             {
70                 let ($(ref mut $B,)*) = self.t;
71 
72                 // NOTE: Just like iter::Zip, we check the iterators
73                 // for None in order. We may finish unevenly (some
74                 // iterators gave n + 1 elements, some only n).
75                 $(
76                     let $B = match $B.next() {
77                         None => return None,
78                         Some(elt) => elt
79                     };
80                 )*
81                 Some(($($B,)*))
82             }
83 
84             fn size_hint(&self) -> (usize, Option<usize>)
85             {
86                 let sh = (::std::usize::MAX, None);
87                 let ($(ref $B,)*) = self.t;
88                 $(
89                     let sh = size_hint::min($B.size_hint(), sh);
90                 )*
91                 sh
92             }
93         }
94 
95         #[allow(non_snake_case)]
96         impl<$($B),*> ExactSizeIterator for Zip<($($B,)*)> where
97             $(
98                 $B: ExactSizeIterator,
99             )*
100         { }
101     );
102 }
103 
104 impl_zip_iter!(A);
105 impl_zip_iter!(A, B);
106 impl_zip_iter!(A, B, C);
107 impl_zip_iter!(A, B, C, D);
108 impl_zip_iter!(A, B, C, D, E);
109 impl_zip_iter!(A, B, C, D, E, F);
110 impl_zip_iter!(A, B, C, D, E, F, G);
111 impl_zip_iter!(A, B, C, D, E, F, G, H);
112