Coverage Report

Created: 2026-01-19 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/itertools-0.14.0/src/zip_longest.rs
Line
Count
Source
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.
24
0
pub fn zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U>
25
0
where
26
0
    T: Iterator,
27
0
    U: Iterator,
28
{
29
0
    ZipLongest {
30
0
        a: a.fuse(),
31
0
        b: b.fuse(),
32
0
    }
33
0
}
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]
43
0
    fn next(&mut self) -> Option<Self::Item> {
44
0
        match (self.a.next(), self.b.next()) {
45
0
            (None, None) => None,
46
0
            (Some(a), None) => Some(EitherOrBoth::Left(a)),
47
0
            (None, Some(b)) => Some(EitherOrBoth::Right(b)),
48
0
            (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
49
        }
50
0
    }
51
52
    #[inline]
53
0
    fn size_hint(&self) -> (usize, Option<usize>) {
54
0
        size_hint::max(self.a.size_hint(), self.b.size_hint())
55
0
    }
56
57
    #[inline]
58
0
    fn fold<B, F>(self, init: B, mut f: F) -> B
59
0
    where
60
0
        Self: Sized,
61
0
        F: FnMut(B, Self::Item) -> B,
62
    {
63
0
        let Self { mut a, mut b } = self;
64
0
        let res = a.try_fold(init, |init, a| match b.next() {
65
0
            Some(b) => Ok(f(init, EitherOrBoth::Both(a, b))),
66
0
            None => Err(f(init, EitherOrBoth::Left(a))),
67
0
        });
68
0
        match res {
69
0
            Ok(acc) => b.map(EitherOrBoth::Right).fold(acc, f),
70
0
            Err(acc) => a.map(EitherOrBoth::Left).fold(acc, f),
71
        }
72
0
    }
73
}
74
75
impl<T, U> DoubleEndedIterator for ZipLongest<T, U>
76
where
77
    T: DoubleEndedIterator + ExactSizeIterator,
78
    U: DoubleEndedIterator + ExactSizeIterator,
79
{
80
    #[inline]
81
0
    fn next_back(&mut self) -> Option<Self::Item> {
82
0
        match self.a.len().cmp(&self.b.len()) {
83
0
            Equal => match (self.a.next_back(), self.b.next_back()) {
84
0
                (None, None) => None,
85
0
                (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
86
                // These can only happen if .len() is inconsistent with .next_back()
87
0
                (Some(a), None) => Some(EitherOrBoth::Left(a)),
88
0
                (None, Some(b)) => Some(EitherOrBoth::Right(b)),
89
            },
90
0
            Greater => self.a.next_back().map(EitherOrBoth::Left),
91
0
            Less => self.b.next_back().map(EitherOrBoth::Right),
92
        }
93
0
    }
94
95
0
    fn rfold<B, F>(self, mut init: B, mut f: F) -> B
96
0
    where
97
0
        F: FnMut(B, Self::Item) -> B,
98
    {
99
0
        let Self { mut a, mut b } = self;
100
0
        let a_len = a.len();
101
0
        let b_len = b.len();
102
0
        match a_len.cmp(&b_len) {
103
0
            Equal => {}
104
            Greater => {
105
0
                init = a
106
0
                    .by_ref()
107
0
                    .rev()
108
0
                    .take(a_len - b_len)
109
0
                    .map(EitherOrBoth::Left)
110
0
                    .fold(init, &mut f)
111
            }
112
            Less => {
113
0
                init = b
114
0
                    .by_ref()
115
0
                    .rev()
116
0
                    .take(b_len - a_len)
117
0
                    .map(EitherOrBoth::Right)
118
0
                    .fold(init, &mut f)
119
            }
120
        }
121
0
        a.rfold(init, |acc, item_a| {
122
0
            f(acc, EitherOrBoth::Both(item_a, b.next_back().unwrap()))
123
0
        })
124
0
    }
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
}