1 use super::size_hint;
2 use std::cmp::Ordering::{Equal, Greater, Less};
3 use std::iter::{Fuse, FusedIterator};
4 
5 use crate::either_or_both::EitherOrBoth;
6 
7 // ZipLongest originally written by SimonSapin,
8 // and dedicated to itertools https://github.com/rust-lang/rust/pull/19283
9 
10 /// An iterator which iterates two other iterators simultaneously
11 /// and wraps the elements in [`EitherOrBoth`].
12 ///
13 /// This iterator is *fused*.
14 ///
15 /// See [`.zip_longest()`](crate::Itertools::zip_longest) for more information.
16 #[derive(Clone, Debug)]
17 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
18 pub struct ZipLongest<T, U> {
19     a: Fuse<T>,
20     b: Fuse<U>,
21 }
22 
23 /// Create a new `ZipLongest` iterator.
zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U> where T: Iterator, U: Iterator,24 pub fn zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U>
25 where
26     T: Iterator,
27     U: Iterator,
28 {
29     ZipLongest {
30         a: a.fuse(),
31         b: b.fuse(),
32     }
33 }
34 
35 impl<T, U> Iterator for ZipLongest<T, U>
36 where
37     T: Iterator,
38     U: Iterator,
39 {
40     type Item = EitherOrBoth<T::Item, U::Item>;
41 
42     #[inline]
next(&mut self) -> Option<Self::Item>43     fn next(&mut self) -> Option<Self::Item> {
44         match (self.a.next(), self.b.next()) {
45             (None, None) => None,
46             (Some(a), None) => Some(EitherOrBoth::Left(a)),
47             (None, Some(b)) => Some(EitherOrBoth::Right(b)),
48             (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
49         }
50     }
51 
52     #[inline]
size_hint(&self) -> (usize, Option<usize>)53     fn size_hint(&self) -> (usize, Option<usize>) {
54         size_hint::max(self.a.size_hint(), self.b.size_hint())
55     }
56 
57     #[inline]
fold<B, F>(self, init: B, mut f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B,58     fn fold<B, F>(self, init: B, mut f: F) -> B
59     where
60         Self: Sized,
61         F: FnMut(B, Self::Item) -> B,
62     {
63         let Self { mut a, mut b } = self;
64         let res = a.try_fold(init, |init, a| match b.next() {
65             Some(b) => Ok(f(init, EitherOrBoth::Both(a, b))),
66             None => Err(f(init, EitherOrBoth::Left(a))),
67         });
68         match res {
69             Ok(acc) => b.map(EitherOrBoth::Right).fold(acc, f),
70             Err(acc) => a.map(EitherOrBoth::Left).fold(acc, f),
71         }
72     }
73 }
74 
75 impl<T, U> DoubleEndedIterator for ZipLongest<T, U>
76 where
77     T: DoubleEndedIterator + ExactSizeIterator,
78     U: DoubleEndedIterator + ExactSizeIterator,
79 {
80     #[inline]
next_back(&mut self) -> Option<Self::Item>81     fn next_back(&mut self) -> Option<Self::Item> {
82         match self.a.len().cmp(&self.b.len()) {
83             Equal => match (self.a.next_back(), self.b.next_back()) {
84                 (None, None) => None,
85                 (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
86                 // These can only happen if .len() is inconsistent with .next_back()
87                 (Some(a), None) => Some(EitherOrBoth::Left(a)),
88                 (None, Some(b)) => Some(EitherOrBoth::Right(b)),
89             },
90             Greater => self.a.next_back().map(EitherOrBoth::Left),
91             Less => self.b.next_back().map(EitherOrBoth::Right),
92         }
93     }
94 
rfold<B, F>(self, mut init: B, mut f: F) -> B where F: FnMut(B, Self::Item) -> B,95     fn rfold<B, F>(self, mut init: B, mut f: F) -> B
96     where
97         F: FnMut(B, Self::Item) -> B,
98     {
99         let Self { mut a, mut b } = self;
100         let a_len = a.len();
101         let b_len = b.len();
102         match a_len.cmp(&b_len) {
103             Equal => {}
104             Greater => {
105                 init = a
106                     .by_ref()
107                     .rev()
108                     .take(a_len - b_len)
109                     .map(EitherOrBoth::Left)
110                     .fold(init, &mut f)
111             }
112             Less => {
113                 init = b
114                     .by_ref()
115                     .rev()
116                     .take(b_len - a_len)
117                     .map(EitherOrBoth::Right)
118                     .fold(init, &mut f)
119             }
120         }
121         a.rfold(init, |acc, item_a| {
122             f(acc, EitherOrBoth::Both(item_a, b.next_back().unwrap()))
123         })
124     }
125 }
126 
127 impl<T, U> ExactSizeIterator for ZipLongest<T, U>
128 where
129     T: ExactSizeIterator,
130     U: ExactSizeIterator,
131 {
132 }
133 
134 impl<T, U> FusedIterator for ZipLongest<T, U>
135 where
136     T: Iterator,
137     U: Iterator,
138 {
139 }
140