zip_long/
lib.rs

1#[cfg(test)]
2mod tests;
3use std::iter::FusedIterator;
4/// Zip together two iterators, creating a single iterator that yields the item(s) in parallel until the longer iterator is exhausted.
5/// Unlike the zip iterator adaptor in `::std::iter`, these adaptors yield elements until the LONGER iterator is exhausted.
6/// ```
7/// use zip::Zip;
8/// ```
9pub trait Zip: IntoIterator + Sized {
10    /// zip together two iterators. when the shorter iterator runs out of items, replace them with fill until the longer iterator is exhausted.
11    /// ```
12    /// # use zip::Zip;
13    /// let mut i: u8 = 0;
14    /// let filler = || {
15    ///    let c = (b'a' + i) as char;
16    ///     i += 1;
17    ///     c
18    ///  };
19    /// let want = vec![('A', 'a'), ('B', 'b'), ('C', 'c'), ('D', 'd')];
20    /// let got: Vec<(char, char)> = vec!['A', 'B', 'C', 'D'].zip_fill(Vec::new(), filler).collect();
21    /// assert_eq!(want, got);
22    /// ```
23    fn zip_fill<R, F>(self, r: R, fill: F) -> Filler<Self::IntoIter, R::IntoIter, F>
24    where
25        R: IntoIterator<Item = Self::Item>,
26        F: FnMut() -> Self::Item,
27    {
28        Filler {
29            q: self.into_iter(),
30            r: r.into_iter(),
31            fill,
32        }
33    }
34    /// zip together two iterators. when the shorter iterator runs out of items, replace them with T::default until the longer iterator is exhausted.
35    ///
36    /// ```
37    /// # use zip::Zip;
38    /// let want = vec![(1, 2), (3, 4), (5, 6), (0, 8)];
39    /// let got: Vec<(usize, usize)> = vec![1, 3, 5].zip_fill_default(vec![2, 4, 6, 8]).collect();
40    /// assert_eq!(want, got);
41    /// ```
42    fn zip_fill_default<R>(self, r: R) -> Filler<Self::IntoIter, R::IntoIter, fn() -> Self::Item>
43    where
44        R: IntoIterator<Item = Self::Item>,
45        Self::Item: Default,
46    {
47        Filler {
48            q: self.into_iter(),
49            r: r.into_iter(),
50            fill: Self::Item::default,
51        }
52    }
53    /// zip together two iterators. when the shorter iterator runs out of items, replace them with clones of `item` until the longer iterator is exhausted.
54    /// ```
55    /// # use zip::Zip;
56    /// let q = vec![0_usize; 4];
57    /// let r = vec![1_usize; 7];
58    /// let want = vec![(0_usize, 1_usize); 7];
59    /// let got: Vec<(usize, usize)> = q.into_iter().zip_fill_with(r, 0).collect();
60    /// assert_eq!(want, got);
61    /// ```
62    fn zip_fill_with<R>(self, r: R, item: Self::Item) -> FillerWith<Self::IntoIter, R::IntoIter>
63    where
64        R: IntoIterator<Item = Self::Item>,
65        Self::Item: Clone,
66    {
67        FillerWith {
68            q: self.into_iter(),
69            r: r.into_iter(),
70            item,
71        }
72    }
73}
74
75impl<I: IntoIterator> Zip for I {}
76
77#[derive(Debug)]
78/// Filler zips together two iterators using the provided closure to fill in for the shorter iterator once it is exhausted.
79pub struct Filler<Q, R, F>
80where
81    Q: Iterator,
82    R: Iterator<Item = Q::Item>,
83    F: FnMut() -> Q::Item,
84{
85    q: Q,
86    r: R,
87    fill: F,
88}
89
90#[derive(Debug)]
91/// FillerWith zips together two iterators using clones of the provided item to fill in for the shorter iterator once is is exhausted.
92pub struct FillerWith<Q: Iterator, R: Iterator<Item = Q::Item>> {
93    q: Q,
94    r: R,
95    item: Q::Item,
96}
97
98impl<Q, R> Iterator for FillerWith<Q, R>
99where
100    Q: Iterator,
101    R: Iterator<Item = Q::Item>,
102    Q::Item: Clone,
103{
104    type Item = (Q::Item, Q::Item);
105    fn next(&mut self) -> Option<Self::Item> {
106        match (self.q.next(), self.r.next()) {
107            (None, None) => None,
108            (Some(q), None) => Some((q, self.item.clone())),
109            (None, Some(r)) => Some((self.item.clone(), r)),
110            (Some(q), Some(r)) => Some((q, r)),
111        }
112    }
113
114    fn size_hint(&self) -> (usize, Option<usize>) {
115        size_hint(self.q.size_hint(), self.r.size_hint())
116    }
117}
118
119impl<Q, R, F> Iterator for Filler<Q, R, F>
120where
121    Q: Iterator,
122    R: Iterator<Item = Q::Item>,
123    F: FnMut() -> Q::Item,
124{
125    type Item = (Q::Item, Q::Item);
126    fn next(&mut self) -> Option<Self::Item> {
127        match (self.q.next(), self.r.next()) {
128            (None, None) => None,
129            (Some(q), None) => Some((q, (self.fill)())),
130            (None, Some(r)) => Some(((self.fill)(), r)),
131            (Some(q), Some(r)) => Some((q, r)),
132        }
133    }
134    fn size_hint(&self) -> (usize, Option<usize>) {
135        size_hint(self.q.size_hint(), self.r.size_hint())
136    }
137}
138
139#[inline]
140fn size_hint(
141    (min_a, max_a): (usize, Option<usize>),
142    (min_b, max_b): (usize, Option<usize>),
143) -> (usize, Option<usize>) {
144    let min = usize::max(min_a, min_b); // we have at least as many elements as the larger minimum
145    let max = if let (Some(a), Some(b)) = (max_a, max_b) {
146        Some(usize::max(a, b))
147    } else {
148        None
149    };
150    (min, max)
151}
152
153impl<Q, R> ExactSizeIterator for FillerWith<Q, R>
154where
155    Q: ExactSizeIterator,
156    R: ExactSizeIterator<Item = Q::Item>,
157    Q::Item: Clone,
158{}
159impl<Q, R> FusedIterator for FillerWith<Q, R>
160where
161    Q: FusedIterator,
162    R: FusedIterator<Item = Q::Item>,
163    Q::Item: Clone,
164{}
165
166impl<Q, R, F> ExactSizeIterator for Filler<Q, R, F>
167where
168    Q: ExactSizeIterator,
169    R: ExactSizeIterator<Item = Q::Item>,
170    F: FnMut() -> Q::Item,
171{}
172
173impl<Q, R, F> FusedIterator for Filler<Q, R, F>
174where
175    Q: FusedIterator,
176    R: FusedIterator<Item = Q::Item>,
177    F: FnMut() -> Q::Item,
178{}