Skip to content

Commit 38805c6

Browse files
committed
add inner_front,inner_back to FlattenOk and update methods
1 parent 4c09d13 commit 38805c6

File tree

1 file changed

+44
-28
lines changed

1 file changed

+44
-28
lines changed

src/flatten_ok.rs

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
use crate::size_hint;
12
use std::{fmt, iter::FusedIterator};
23

34
pub fn flatten_ok<I, T, E>(iter: I) -> FlattenOk<I, T, E>
45
where
56
I: Iterator<Item = Result<T, E>>,
67
T: IntoIterator,
78
{
8-
FlattenOk { iter, inner: None }
9+
FlattenOk {
10+
iter,
11+
inner_front: None,
12+
inner_back: None,
13+
}
914
}
1015

1116
/// An iterator adaptor that flattens `Result::Ok` values and
@@ -19,7 +24,8 @@ where
1924
T: IntoIterator,
2025
{
2126
iter: I,
22-
inner: Option<T::IntoIter>,
27+
inner_front: Option<T::IntoIter>,
28+
inner_back: Option<T::IntoIter>,
2329
}
2430

2531
impl<I, T, E> Iterator for FlattenOk<I, T, E>
@@ -31,45 +37,54 @@ where
3137

3238
fn next(&mut self) -> Option<Self::Item> {
3339
loop {
34-
if let Some(inner) = &mut self.inner {
40+
// Handle the front inner iterator.
41+
if let Some(inner) = &mut self.inner_front {
3542
if let Some(item) = inner.next() {
3643
return Some(Ok(item));
3744
} else {
3845
// This is necessary for the iterator to implement `FusedIterator`
3946
// with only the orginal iterator being fused.
40-
self.inner = None;
47+
self.inner_front = None;
4148
}
4249
}
4350

4451
match self.iter.next() {
45-
Some(Ok(ok)) => self.inner = Some(ok.into_iter()),
52+
Some(Ok(ok)) => self.inner_front = Some(ok.into_iter()),
4653
Some(Err(e)) => return Some(Err(e)),
47-
None => return None,
54+
None => {
55+
// Handle the back inner iterator.
56+
if let Some(inner) = &mut self.inner_back {
57+
if let Some(item) = inner.next() {
58+
return Some(Ok(item));
59+
} else {
60+
// This is necessary for the iterator to implement `FusedIterator`
61+
// with only the orginal iterator being fused.
62+
self.inner_back = None;
63+
}
64+
} else {
65+
return None;
66+
}
67+
}
4868
}
4969
}
5070
}
5171

5272
fn size_hint(&self) -> (usize, Option<usize>) {
53-
if let Some(inner) = &self.inner {
54-
// If we have an inner iterator, then its lower bound is our lower bound,
55-
// but we still don't know the upper bound.
56-
let (inner_lower, inner_higher) = inner.size_hint();
57-
let (_, outer_higher) = self.iter.size_hint();
58-
if outer_higher == Some(0) {
59-
// If there is nothing remaining in the outer iterator, we know the upper bound.
60-
(inner_lower, inner_higher)
61-
} else {
62-
// However, if the outer iterator could have more items in it, we don't
63-
// know the upper bound.
64-
(inner_lower, None)
65-
}
66-
} else if self.iter.size_hint() == (0, Some(0)) {
67-
// If the outer iterator is empty, we have no items.
68-
(0, Some(0))
69-
} else {
70-
// Otherwise we do not know anything about the number of items.
71-
(0, None)
72-
}
73+
let inner_hint = |inner: &Option<T::IntoIter>| {
74+
inner
75+
.as_ref()
76+
.map(Iterator::size_hint)
77+
.unwrap_or((0, Some(0)))
78+
};
79+
let inner_front = inner_hint(&self.inner_front);
80+
let inner_back = inner_hint(&self.inner_back);
81+
// The outer iterator `Ok` case could be (0, None) as we don't know its size_hint yet.
82+
let outer = match self.iter.size_hint() {
83+
(0, Some(0)) => (0, Some(0)),
84+
_ => (0, None),
85+
};
86+
87+
size_hint::add(size_hint::add(inner_front, inner_back), outer)
7388
}
7489
}
7590

@@ -80,7 +95,7 @@ where
8095
T::IntoIter: Clone,
8196
{
8297
#[inline]
83-
clone_fields!(iter, inner);
98+
clone_fields!(iter, inner_front, inner_back);
8499
}
85100

86101
impl<I, T, E> fmt::Debug for FlattenOk<I, T, E>
@@ -92,7 +107,8 @@ where
92107
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93108
f.debug_struct("FlattenOk")
94109
.field("iter", &self.iter)
95-
.field("inner", &self.inner)
110+
.field("inner_front", &self.inner_front)
111+
.field("inner_back", &self.inner_back)
96112
.finish()
97113
}
98114
}

0 commit comments

Comments
 (0)