]> git.proxmox.com Git - rustc.git/blob - src/vendor/itertools/src/zip_longest.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / vendor / itertools / src / zip_longest.rs
1 use std::cmp::Ordering::{Equal, Greater, Less};
2 use super::size_hint;
3 use std::iter::Fuse;
4 use self::EitherOrBoth::{Right, Left, Both};
5
6 // ZipLongest originally written by SimonSapin,
7 // and dedicated to itertools https://github.com/rust-lang/rust/pull/19283
8
9 /// An iterator which iterates two other iterators simultaneously
10 ///
11 /// This iterator is *fused*.
12 ///
13 /// See [`.zip_longest()`](../trait.Itertools.html#method.zip_longest) for more information.
14 #[derive(Clone)]
15 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
16 pub struct ZipLongest<T, U> {
17 a: Fuse<T>,
18 b: Fuse<U>,
19 }
20
21 /// Create a new `ZipLongest` iterator.
22 pub fn zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U>
23 where T: Iterator,
24 U: Iterator
25 {
26 ZipLongest {
27 a: a.fuse(),
28 b: b.fuse(),
29 }
30 }
31
32 impl<T, U> Iterator for ZipLongest<T, U>
33 where T: Iterator,
34 U: Iterator
35 {
36 type Item = EitherOrBoth<T::Item, U::Item>;
37
38 #[inline]
39 fn next(&mut self) -> Option<Self::Item> {
40 match (self.a.next(), self.b.next()) {
41 (None, None) => None,
42 (Some(a), None) => Some(Left(a)),
43 (None, Some(b)) => Some(Right(b)),
44 (Some(a), Some(b)) => Some(Both(a, b)),
45 }
46 }
47
48 #[inline]
49 fn size_hint(&self) -> (usize, Option<usize>) {
50 size_hint::max(self.a.size_hint(), self.b.size_hint())
51 }
52 }
53
54 impl<T, U> DoubleEndedIterator for ZipLongest<T, U>
55 where T: DoubleEndedIterator + ExactSizeIterator,
56 U: DoubleEndedIterator + ExactSizeIterator
57 {
58 #[inline]
59 fn next_back(&mut self) -> Option<Self::Item> {
60 match self.a.len().cmp(&self.b.len()) {
61 Equal => match (self.a.next_back(), self.b.next_back()) {
62 (None, None) => None,
63 (Some(a), Some(b)) => Some(Both(a, b)),
64 // These can only happen if .len() is inconsistent with .next_back()
65 (Some(a), None) => Some(Left(a)),
66 (None, Some(b)) => Some(Right(b)),
67 },
68 Greater => self.a.next_back().map(Left),
69 Less => self.b.next_back().map(Right),
70 }
71 }
72 }
73
74 impl<T, U> ExactSizeIterator for ZipLongest<T, U>
75 where T: ExactSizeIterator,
76 U: ExactSizeIterator
77 {}
78
79
80 /// A value yielded by `ZipLongest`.
81 /// Contains one or two values, depending on which of the input iterators are exhausted.
82 ///
83 /// See [`.zip_longest()`](trait.Itertools.html#method.zip_longest) for more information.
84 #[derive(Clone, PartialEq, Eq, Debug)]
85 pub enum EitherOrBoth<A, B> {
86 /// Neither input iterator is exhausted yet, yielding two values.
87 Both(A, B),
88 /// The parameter iterator of `.zip_longest()` is exhausted,
89 /// only yielding a value from the `self` iterator.
90 Left(A),
91 /// The `self` iterator of `.zip_longest()` is exhausted,
92 /// only yielding a value from the parameter iterator.
93 Right(B),
94 }