itertools/
ziptuple.rs

1use super::size_hint;
2
3/// See [`multizip`] 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/// ```
27/// use itertools::multizip;
28///
29/// // iterate over three sequences side-by-side
30/// let mut results = [0, 0, 0, 0];
31/// let inputs = [3, 7, 9, 6];
32///
33/// for (r, index, input) in multizip((&mut results, 0..10, &inputs)) {
34///     *r = index * 10 + input;
35/// }
36///
37/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]);
38/// ```
39/// [`izip!()`]: crate::izip
40pub fn multizip<T, U>(t: U) -> Zip<T>
41    where Zip<T>: From<U>,
42          Zip<T>: Iterator,
43{
44    Zip::from(t)
45}
46
47macro_rules! impl_zip_iter {
48    ($($B:ident),*) => (
49        #[allow(non_snake_case)]
50        impl<$($B: IntoIterator),*> From<($($B,)*)> for Zip<($($B::IntoIter,)*)> {
51            fn from(t: ($($B,)*)) -> Self {
52                let ($($B,)*) = t;
53                Zip { t: ($($B.into_iter(),)*) }
54            }
55        }
56
57        #[allow(non_snake_case)]
58        #[allow(unused_assignments)]
59        impl<$($B),*> Iterator for Zip<($($B,)*)>
60            where
61            $(
62                $B: Iterator,
63            )*
64        {
65            type Item = ($($B::Item,)*);
66
67            fn next(&mut self) -> Option<Self::Item>
68            {
69                let ($(ref mut $B,)*) = self.t;
70
71                // NOTE: Just like iter::Zip, we check the iterators
72                // for None in order. We may finish unevenly (some
73                // iterators gave n + 1 elements, some only n).
74                $(
75                    let $B = match $B.next() {
76                        None => return None,
77                        Some(elt) => elt
78                    };
79                )*
80                Some(($($B,)*))
81            }
82
83            fn size_hint(&self) -> (usize, Option<usize>)
84            {
85                let sh = (::std::usize::MAX, None);
86                let ($(ref $B,)*) = self.t;
87                $(
88                    let sh = size_hint::min($B.size_hint(), sh);
89                )*
90                sh
91            }
92        }
93
94        #[allow(non_snake_case)]
95        impl<$($B),*> ExactSizeIterator for Zip<($($B,)*)> where
96            $(
97                $B: ExactSizeIterator,
98            )*
99        { }
100
101        #[allow(non_snake_case)]
102        impl<$($B),*> DoubleEndedIterator for Zip<($($B,)*)> where
103            $(
104                $B: DoubleEndedIterator + ExactSizeIterator,
105            )*
106        {
107            #[inline]
108            fn next_back(&mut self) -> Option<Self::Item> {
109                let ($(ref mut $B,)*) = self.t;
110                let size = *[$( $B.len(), )*].iter().min().unwrap();
111
112                $(
113                    if $B.len() != size {
114                        for _ in 0..$B.len() - size { $B.next_back(); }
115                    }
116                )*
117
118                match ($($B.next_back(),)*) {
119                    ($(Some($B),)*) => Some(($($B,)*)),
120                    _ => None,
121                }
122            }
123        }
124    );
125}
126
127impl_zip_iter!(A);
128impl_zip_iter!(A, B);
129impl_zip_iter!(A, B, C);
130impl_zip_iter!(A, B, C, D);
131impl_zip_iter!(A, B, C, D, E);
132impl_zip_iter!(A, B, C, D, E, F);
133impl_zip_iter!(A, B, C, D, E, F, G);
134impl_zip_iter!(A, B, C, D, E, F, G, H);
135impl_zip_iter!(A, B, C, D, E, F, G, H, I);
136impl_zip_iter!(A, B, C, D, E, F, G, H, I, J);
137impl_zip_iter!(A, B, C, D, E, F, G, H, I, J, K);
138impl_zip_iter!(A, B, C, D, E, F, G, H, I, J, K, L);