1 use std::cmp::Ordering::{Equal, Greater, Less};
2 use super::size_hint;
3 use std::iter::Fuse;
4
5 use 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 ///
12 /// This iterator is *fused*.
13 ///
14 /// See [`.zip_longest()`](../trait.Itertools.html#method.zip_longest) for more information.
15 #[derive(Clone, Debug)]
16 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
17 pub struct ZipLongest<T, U> {
18 a: Fuse<T>,
19 b: Fuse<U>,
20 }
21
22 /// Create a new `ZipLongest` iterator.
zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U> where T: Iterator, U: Iterator23 pub fn zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U>
24 where T: Iterator,
25 U: Iterator
26 {
27 ZipLongest {
28 a: a.fuse(),
29 b: b.fuse(),
30 }
31 }
32
33 impl<T, U> Iterator for ZipLongest<T, U>
34 where T: Iterator,
35 U: Iterator
36 {
37 type Item = EitherOrBoth<T::Item, U::Item>;
38
39 #[inline]
next(&mut self) -> Option<Self::Item>40 fn next(&mut self) -> Option<Self::Item> {
41 match (self.a.next(), self.b.next()) {
42 (None, None) => None,
43 (Some(a), None) => Some(EitherOrBoth::Left(a)),
44 (None, Some(b)) => Some(EitherOrBoth::Right(b)),
45 (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
46 }
47 }
48
49 #[inline]
size_hint(&self) -> (usize, Option<usize>)50 fn size_hint(&self) -> (usize, Option<usize>) {
51 size_hint::max(self.a.size_hint(), self.b.size_hint())
52 }
53 }
54
55 impl<T, U> DoubleEndedIterator for ZipLongest<T, U>
56 where T: DoubleEndedIterator + ExactSizeIterator,
57 U: DoubleEndedIterator + ExactSizeIterator
58 {
59 #[inline]
next_back(&mut self) -> Option<Self::Item>60 fn next_back(&mut self) -> Option<Self::Item> {
61 match self.a.len().cmp(&self.b.len()) {
62 Equal => match (self.a.next_back(), self.b.next_back()) {
63 (None, None) => None,
64 (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
65 // These can only happen if .len() is inconsistent with .next_back()
66 (Some(a), None) => Some(EitherOrBoth::Left(a)),
67 (None, Some(b)) => Some(EitherOrBoth::Right(b)),
68 },
69 Greater => self.a.next_back().map(EitherOrBoth::Left),
70 Less => self.b.next_back().map(EitherOrBoth::Right),
71 }
72 }
73 }
74
75 impl<T, U> ExactSizeIterator for ZipLongest<T, U>
76 where T: ExactSizeIterator,
77 U: ExactSizeIterator
78 {}
79