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