Coverage Report

Created: 2025-07-01 06:50

/rust/registry/src/index.crates.io-6f17d22bba15001f/itertools-0.12.1/src/zip_longest.rs
Line
Count
Source (jump to first uncovered line)
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
///
12
/// This iterator is *fused*.
13
///
14
/// See [`.zip_longest()`](crate::Itertools::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.
23
0
pub fn zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U>
24
0
where
25
0
    T: Iterator,
26
0
    U: Iterator,
27
0
{
28
0
    ZipLongest {
29
0
        a: a.fuse(),
30
0
        b: b.fuse(),
31
0
    }
32
0
}
33
34
impl<T, U> Iterator for ZipLongest<T, U>
35
where
36
    T: Iterator,
37
    U: Iterator,
38
{
39
    type Item = EitherOrBoth<T::Item, U::Item>;
40
41
    #[inline]
42
0
    fn next(&mut self) -> Option<Self::Item> {
43
0
        match (self.a.next(), self.b.next()) {
44
0
            (None, None) => None,
45
0
            (Some(a), None) => Some(EitherOrBoth::Left(a)),
46
0
            (None, Some(b)) => Some(EitherOrBoth::Right(b)),
47
0
            (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
48
        }
49
0
    }
50
51
    #[inline]
52
0
    fn size_hint(&self) -> (usize, Option<usize>) {
53
0
        size_hint::max(self.a.size_hint(), self.b.size_hint())
54
0
    }
55
56
    #[inline]
57
0
    fn fold<B, F>(self, init: B, mut f: F) -> B
58
0
    where
59
0
        Self: Sized,
60
0
        F: FnMut(B, Self::Item) -> B,
61
0
    {
62
0
        let Self { mut a, mut b } = self;
63
0
        let res = a.try_fold(init, |init, a| match b.next() {
64
0
            Some(b) => Ok(f(init, EitherOrBoth::Both(a, b))),
65
0
            None => Err(f(init, EitherOrBoth::Left(a))),
66
0
        });
67
0
        match res {
68
0
            Ok(acc) => b.map(EitherOrBoth::Right).fold(acc, f),
69
0
            Err(acc) => a.map(EitherOrBoth::Left).fold(acc, f),
70
        }
71
0
    }
72
}
73
74
impl<T, U> DoubleEndedIterator for ZipLongest<T, U>
75
where
76
    T: DoubleEndedIterator + ExactSizeIterator,
77
    U: DoubleEndedIterator + ExactSizeIterator,
78
{
79
    #[inline]
80
0
    fn next_back(&mut self) -> Option<Self::Item> {
81
0
        match self.a.len().cmp(&self.b.len()) {
82
0
            Equal => match (self.a.next_back(), self.b.next_back()) {
83
0
                (None, None) => None,
84
0
                (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
85
                // These can only happen if .len() is inconsistent with .next_back()
86
0
                (Some(a), None) => Some(EitherOrBoth::Left(a)),
87
0
                (None, Some(b)) => Some(EitherOrBoth::Right(b)),
88
            },
89
0
            Greater => self.a.next_back().map(EitherOrBoth::Left),
90
0
            Less => self.b.next_back().map(EitherOrBoth::Right),
91
        }
92
0
    }
93
94
0
    fn rfold<B, F>(self, mut init: B, mut f: F) -> B
95
0
    where
96
0
        F: FnMut(B, Self::Item) -> B,
97
0
    {
98
0
        let Self { mut a, mut b } = self;
99
0
        let a_len = a.len();
100
0
        let b_len = b.len();
101
0
        match a_len.cmp(&b_len) {
102
0
            Equal => {}
103
            Greater => {
104
0
                init = a
105
0
                    .by_ref()
106
0
                    .rev()
107
0
                    .take(a_len - b_len)
108
0
                    .map(EitherOrBoth::Left)
109
0
                    .fold(init, &mut f)
110
            }
111
            Less => {
112
0
                init = b
113
0
                    .by_ref()
114
0
                    .rev()
115
0
                    .take(b_len - a_len)
116
0
                    .map(EitherOrBoth::Right)
117
0
                    .fold(init, &mut f)
118
            }
119
        }
120
0
        a.rfold(init, |acc, item_a| {
121
0
            f(acc, EitherOrBoth::Both(item_a, b.next_back().unwrap()))
122
0
        })
123
0
    }
124
}
125
126
impl<T, U> ExactSizeIterator for ZipLongest<T, U>
127
where
128
    T: ExactSizeIterator,
129
    U: ExactSizeIterator,
130
{
131
}
132
133
impl<T, U> FusedIterator for ZipLongest<T, U>
134
where
135
    T: Iterator,
136
    U: Iterator,
137
{
138
}