Coverage Report

Created: 2025-11-20 14:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/build/cargo-vendor-dir/itertools-0.14.0/src/flatten_ok.rs
Line
Count
Source
1
use crate::size_hint;
2
use std::{
3
    fmt,
4
    iter::{DoubleEndedIterator, FusedIterator},
5
};
6
7
0
pub fn flatten_ok<I, T, E>(iter: I) -> FlattenOk<I, T, E>
8
0
where
9
0
    I: Iterator<Item = Result<T, E>>,
10
0
    T: IntoIterator,
11
0
{
12
0
    FlattenOk {
13
0
        iter,
14
0
        inner_front: None,
15
0
        inner_back: None,
16
0
    }
17
0
}
18
19
/// An iterator adaptor that flattens `Result::Ok` values and
20
/// allows `Result::Err` values through unchanged.
21
///
22
/// See [`.flatten_ok()`](crate::Itertools::flatten_ok) for more information.
23
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
24
pub struct FlattenOk<I, T, E>
25
where
26
    I: Iterator<Item = Result<T, E>>,
27
    T: IntoIterator,
28
{
29
    iter: I,
30
    inner_front: Option<T::IntoIter>,
31
    inner_back: Option<T::IntoIter>,
32
}
33
34
impl<I, T, E> Iterator for FlattenOk<I, T, E>
35
where
36
    I: Iterator<Item = Result<T, E>>,
37
    T: IntoIterator,
38
{
39
    type Item = Result<T::Item, E>;
40
41
0
    fn next(&mut self) -> Option<Self::Item> {
42
        loop {
43
            // Handle the front inner iterator.
44
0
            if let Some(inner) = &mut self.inner_front {
45
0
                if let Some(item) = inner.next() {
46
0
                    return Some(Ok(item));
47
0
                }
48
0
49
0
                // This is necessary for the iterator to implement `FusedIterator`
50
0
                // with only the original iterator being fused.
51
0
                self.inner_front = None;
52
0
            }
53
54
0
            match self.iter.next() {
55
0
                Some(Ok(ok)) => self.inner_front = Some(ok.into_iter()),
56
0
                Some(Err(e)) => return Some(Err(e)),
57
                None => {
58
                    // Handle the back inner iterator.
59
0
                    if let Some(inner) = &mut self.inner_back {
60
0
                        if let Some(item) = inner.next() {
61
0
                            return Some(Ok(item));
62
0
                        }
63
0
64
0
                        // This is necessary for the iterator to implement `FusedIterator`
65
0
                        // with only the original iterator being fused.
66
0
                        self.inner_back = None;
67
                    } else {
68
0
                        return None;
69
                    }
70
                }
71
            }
72
        }
73
0
    }
74
75
0
    fn fold<B, F>(self, init: B, mut f: F) -> B
76
0
    where
77
0
        Self: Sized,
78
0
        F: FnMut(B, Self::Item) -> B,
79
0
    {
80
        // Front
81
0
        let mut acc = match self.inner_front {
82
0
            Some(x) => x.fold(init, |a, o| f(a, Ok(o))),
83
0
            None => init,
84
        };
85
86
0
        acc = self.iter.fold(acc, |acc, x| match x {
87
0
            Ok(it) => it.into_iter().fold(acc, |a, o| f(a, Ok(o))),
88
0
            Err(e) => f(acc, Err(e)),
89
0
        });
90
0
91
0
        // Back
92
0
        match self.inner_back {
93
0
            Some(x) => x.fold(acc, |a, o| f(a, Ok(o))),
94
0
            None => acc,
95
        }
96
0
    }
97
98
0
    fn size_hint(&self) -> (usize, Option<usize>) {
99
0
        let inner_hint = |inner: &Option<T::IntoIter>| {
100
0
            inner
101
0
                .as_ref()
102
0
                .map(Iterator::size_hint)
103
0
                .unwrap_or((0, Some(0)))
104
0
        };
105
0
        let inner_front = inner_hint(&self.inner_front);
106
0
        let inner_back = inner_hint(&self.inner_back);
107
        // The outer iterator `Ok` case could be (0, None) as we don't know its size_hint yet.
108
0
        let outer = match self.iter.size_hint() {
109
0
            (0, Some(0)) => (0, Some(0)),
110
0
            _ => (0, None),
111
        };
112
113
0
        size_hint::add(size_hint::add(inner_front, inner_back), outer)
114
0
    }
115
}
116
117
impl<I, T, E> DoubleEndedIterator for FlattenOk<I, T, E>
118
where
119
    I: DoubleEndedIterator<Item = Result<T, E>>,
120
    T: IntoIterator,
121
    T::IntoIter: DoubleEndedIterator,
122
{
123
0
    fn next_back(&mut self) -> Option<Self::Item> {
124
        loop {
125
            // Handle the back inner iterator.
126
0
            if let Some(inner) = &mut self.inner_back {
127
0
                if let Some(item) = inner.next_back() {
128
0
                    return Some(Ok(item));
129
0
                }
130
0
131
0
                // This is necessary for the iterator to implement `FusedIterator`
132
0
                // with only the original iterator being fused.
133
0
                self.inner_back = None;
134
0
            }
135
136
0
            match self.iter.next_back() {
137
0
                Some(Ok(ok)) => self.inner_back = Some(ok.into_iter()),
138
0
                Some(Err(e)) => return Some(Err(e)),
139
                None => {
140
                    // Handle the front inner iterator.
141
0
                    if let Some(inner) = &mut self.inner_front {
142
0
                        if let Some(item) = inner.next_back() {
143
0
                            return Some(Ok(item));
144
0
                        }
145
0
146
0
                        // This is necessary for the iterator to implement `FusedIterator`
147
0
                        // with only the original iterator being fused.
148
0
                        self.inner_front = None;
149
                    } else {
150
0
                        return None;
151
                    }
152
                }
153
            }
154
        }
155
0
    }
156
157
0
    fn rfold<B, F>(self, init: B, mut f: F) -> B
158
0
    where
159
0
        Self: Sized,
160
0
        F: FnMut(B, Self::Item) -> B,
161
0
    {
162
        // Back
163
0
        let mut acc = match self.inner_back {
164
0
            Some(x) => x.rfold(init, |a, o| f(a, Ok(o))),
165
0
            None => init,
166
        };
167
168
0
        acc = self.iter.rfold(acc, |acc, x| match x {
169
0
            Ok(it) => it.into_iter().rfold(acc, |a, o| f(a, Ok(o))),
170
0
            Err(e) => f(acc, Err(e)),
171
0
        });
172
0
173
0
        // Front
174
0
        match self.inner_front {
175
0
            Some(x) => x.rfold(acc, |a, o| f(a, Ok(o))),
176
0
            None => acc,
177
        }
178
0
    }
179
}
180
181
impl<I, T, E> Clone for FlattenOk<I, T, E>
182
where
183
    I: Iterator<Item = Result<T, E>> + Clone,
184
    T: IntoIterator,
185
    T::IntoIter: Clone,
186
{
187
    clone_fields!(iter, inner_front, inner_back);
188
}
189
190
impl<I, T, E> fmt::Debug for FlattenOk<I, T, E>
191
where
192
    I: Iterator<Item = Result<T, E>> + fmt::Debug,
193
    T: IntoIterator,
194
    T::IntoIter: fmt::Debug,
195
{
196
    debug_fmt_fields!(FlattenOk, iter, inner_front, inner_back);
197
}
198
199
/// Only the iterator being flattened needs to implement [`FusedIterator`].
200
impl<I, T, E> FusedIterator for FlattenOk<I, T, E>
201
where
202
    I: FusedIterator<Item = Result<T, E>>,
203
    T: IntoIterator,
204
{
205
}