array_tool/
iter.rs

1use std::cmp;
2use std::iter::IntoIterator;
3
4#[doc(hidden)]
5#[derive(Clone, Debug)]
6#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
7pub struct ZipOption<A, B> {
8  a: A,
9  b: B,
10  // index and len are only used by the specialized version of zip
11  index: usize,
12  len: usize,
13}
14
15/// Zips to iterators together to the longest length
16/// via Option<(Option<A>, Option<B>)>
17pub trait ZipOpt {
18  /// Zip to iterators to longest length via Option<(Option<A>, Option<B>)> results.
19  /// # Example
20  /// ```
21  /// use array_tool::iter::ZipOpt;
22  ///
23  /// let a = vec!["a","b","c", "d"];
24  /// let b = vec!["c","d"];
25  /// let mut x = a.iter().zip_option(b.iter());
26  ///
27  /// assert_eq!(x.next(), Some((Some(&"a"), Some(&"c"))));
28  /// assert_eq!(x.next(), Some((Some(&"b"), Some(&"d"))));
29  /// assert_eq!(x.next(), Some((Some(&"c"), None)));
30  /// assert_eq!(x.next(), Some((Some(&"d"), None)));
31  /// assert_eq!(x.next(), None);
32  /// ```
33  ///
34  /// # Output
35  /// ```text
36  /// vec![ "a", "b", "c", "d" ]
37  /// ```
38  fn zip_option<U>(self, other: U) -> ZipOption<Self, U::IntoIter>
39    where Self: Sized, U: IntoIterator;
40}
41
42impl<I: Iterator> ZipOpt for I {
43  #[inline]
44  fn zip_option<U>(self, other: U) -> ZipOption<Self, U::IntoIter>
45    where Self: Sized, U: IntoIterator {
46
47    ZipOption::new(self, other.into_iter())
48  }
49}
50
51impl<A, B> Iterator for ZipOption<A, B> where A: Iterator, B: Iterator {
52  type Item = (Option<A::Item>, Option<B::Item>);
53
54  #[inline]
55  fn next(&mut self) -> Option<Self::Item> {
56    ZipImpl::next(self)
57  }
58
59  #[inline]
60  fn size_hint(&self) -> (usize, Option<usize>) {
61    ZipImpl::size_hint(self)
62  }
63
64  #[inline]
65  fn nth(&mut self, n: usize) -> Option<Self::Item> {
66    ZipImpl::nth(self, n)
67  }
68}
69
70#[doc(hidden)]
71impl<A, B> DoubleEndedIterator for ZipOption<A, B> where
72A: DoubleEndedIterator + ExactSizeIterator,
73B: DoubleEndedIterator + ExactSizeIterator,
74{
75  #[inline]
76  fn next_back(&mut self) -> Option<(Option<A::Item>, Option<B::Item>)> {
77    ZipImpl::next_back(self)
78  }
79}
80
81#[doc(hidden)]
82trait ZipImpl<A, B> {
83  type Item;
84  fn new(a: A, b: B) -> Self;
85  fn next(&mut self) -> Option<Self::Item>;
86  fn size_hint(&self) -> (usize, Option<usize>);
87  fn nth(&mut self, n: usize) -> Option<Self::Item>;
88  fn super_nth(&mut self, mut n: usize) -> Option<Self::Item> {
89    while let Some(x) = self.next() {
90      if n == 0 { return Some(x) }
91      n -= 1;
92    }
93    None
94  }
95  fn next_back(&mut self) -> Option<Self::Item>
96    where A: DoubleEndedIterator + ExactSizeIterator,
97          B: DoubleEndedIterator + ExactSizeIterator;
98}
99
100#[doc(hidden)]
101impl<A, B> ZipImpl<A, B> for ZipOption<A, B>
102  where A: Iterator, B: Iterator {
103  type Item = (Option<A::Item>, Option<B::Item>);
104  fn new(a: A, b: B) -> Self {
105    ZipOption {
106      a,
107      b,
108      index: 0, // unused
109      len: 0, // unused
110    }
111  }
112
113  #[inline]
114  fn next(&mut self) -> Option<(Option<A::Item>, Option<B::Item>)> {
115    let first = self.a.next();
116    let second = self.b.next();
117
118    if first.is_some() || second.is_some() {
119      Some((first, second))
120    } else {
121      None
122    }
123  }
124
125  #[inline]
126  fn nth(&mut self, n: usize) -> Option<Self::Item> {
127    self.super_nth(n)
128  }
129
130  #[inline]
131  fn next_back(&mut self) -> Option<(Option<A::Item>, Option<B::Item>)>
132    where A: DoubleEndedIterator + ExactSizeIterator,
133          B: DoubleEndedIterator + ExactSizeIterator {
134    let a_sz = self.a.len();
135    let b_sz = self.b.len();
136    if a_sz != b_sz {
137      // Adjust a, b to equal length
138      if a_sz > b_sz {
139        for _ in 0..a_sz - b_sz { self.a.next_back(); }
140      } else {
141        for _ in 0..b_sz - a_sz { self.b.next_back(); }
142      }
143    }
144    match (self.a.next_back(), self.b.next_back()) {
145      (None, None) => None,
146      (f,s) => Some((f, s)),
147    }
148  }
149
150  #[inline]
151  fn size_hint(&self) -> (usize, Option<usize>) {
152    let (a_lower, a_upper) = self.a.size_hint();
153    let (b_lower, b_upper) = self.b.size_hint();
154
155    let lower = cmp::min(a_lower, b_lower);
156
157    let upper = match (a_upper, b_upper) {
158      (Some(x), Some(y)) => Some(cmp::max(x,y)),
159      (Some(x), None) => Some(x),
160      (None, Some(y)) => Some(y),
161      (None, None) => None
162    };
163
164    (lower, upper)
165  }
166}