itertools/
ziptuple.rs

1use 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"]
6pub 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/// ```
41pub 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
48macro_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
104impl_zip_iter!(A);
105impl_zip_iter!(A, B);
106impl_zip_iter!(A, B, C);
107impl_zip_iter!(A, B, C, D);
108impl_zip_iter!(A, B, C, D, E);
109impl_zip_iter!(A, B, C, D, E, F);
110impl_zip_iter!(A, B, C, D, E, F, G);
111impl_zip_iter!(A, B, C, D, E, F, G, H);