]>
Commit | Line | Data |
---|---|---|
abe05a73 XL |
1 | use super::size_hint; |
2 | ||
3 | /// See [`multizip`](../fn.multizip.html) for more information. | |
4 | #[derive(Clone)] | |
2c00a5a8 | 5 | #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] |
abe05a73 XL |
6 | pub struct Zip<T> { |
7 | t: T, | |
8 | } | |
9 | ||
abe05a73 XL |
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 | /// | |
2c00a5a8 XL |
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 | /// | |
abe05a73 XL |
28 | /// ``` |
29 | /// use itertools::multizip; | |
30 | /// | |
2c00a5a8 XL |
31 | /// // iterate over three sequences side-by-side |
32 | /// let mut results = [0, 0, 0, 0]; | |
33 | /// let inputs = [3, 7, 9, 6]; | |
abe05a73 | 34 | /// |
2c00a5a8 XL |
35 | /// for (r, index, input) in multizip((&mut results, 0..10, &inputs)) { |
36 | /// *r = index * 10 + input; | |
abe05a73 XL |
37 | /// } |
38 | /// | |
2c00a5a8 | 39 | /// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); |
abe05a73 XL |
40 | /// ``` |
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); |