Skip to content

Commit 5ae85f4

Browse files
committed
Auto merge of rust-lang#68820 - WaffleLapkin:remove_finished_from_map_while, r=LukasKalbertodt
Remove `finished` flag from `MapWhile` This PR removes `finished` flag from `MapWhile` as been proposed in rust-lang#66577 (comment). This also resolves open questions of the tracking issue (rust-lang#68537): - `MapWhile` can't implement both + `DoubleEndedIterator` (discussed in rust-lang#66577 (comment) and following comments) + `FusedIterator` (this pr removes `finished` flag, so `MapWhile` isn't fused anymore) - Debug output (this pr removes `finished` flag, so there is no question in including it in debug output) r? @Mark-Simulacrum
2 parents 94d43d6 + e964d71 commit 5ae85f4

File tree

2 files changed

+32
-57
lines changed

2 files changed

+32
-57
lines changed

src/libcore/iter/adapters/mod.rs

+21-47
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,14 @@ where
17681768
}
17691769
}
17701770

1771+
#[stable(feature = "fused", since = "1.26.0")]
1772+
impl<I, P> FusedIterator for TakeWhile<I, P>
1773+
where
1774+
I: FusedIterator,
1775+
P: FnMut(&I::Item) -> bool,
1776+
{
1777+
}
1778+
17711779
/// An iterator that only accepts elements while `predicate` returns `Some(_)`.
17721780
///
17731781
/// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its
@@ -1780,20 +1788,19 @@ where
17801788
#[derive(Clone)]
17811789
pub struct MapWhile<I, P> {
17821790
iter: I,
1783-
finished: bool,
17841791
predicate: P,
17851792
}
17861793

17871794
impl<I, P> MapWhile<I, P> {
17881795
pub(super) fn new(iter: I, predicate: P) -> MapWhile<I, P> {
1789-
MapWhile { iter, finished: false, predicate }
1796+
MapWhile { iter, predicate }
17901797
}
17911798
}
17921799

17931800
#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
17941801
impl<I: fmt::Debug, P> fmt::Debug for MapWhile<I, P> {
17951802
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1796-
f.debug_struct("MapWhile").field("iter", &self.iter).field("flag", &self.finished).finish()
1803+
f.debug_struct("MapWhile").field("iter", &self.iter).finish()
17971804
}
17981805
}
17991806

@@ -1806,65 +1813,32 @@ where
18061813

18071814
#[inline]
18081815
fn next(&mut self) -> Option<B> {
1809-
if self.finished {
1810-
None
1811-
} else {
1812-
let x = self.iter.next()?;
1813-
let ret = (self.predicate)(x);
1814-
self.finished = ret.is_none();
1815-
ret
1816-
}
1816+
let x = self.iter.next()?;
1817+
(self.predicate)(x)
18171818
}
18181819

18191820
#[inline]
18201821
fn size_hint(&self) -> (usize, Option<usize>) {
1821-
if self.finished {
1822-
(0, Some(0))
1823-
} else {
1824-
let (_, upper) = self.iter.size_hint();
1825-
(0, upper) // can't know a lower bound, due to the predicate
1826-
}
1822+
let (_, upper) = self.iter.size_hint();
1823+
(0, upper) // can't know a lower bound, due to the predicate
18271824
}
18281825

18291826
#[inline]
1830-
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
1827+
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R
18311828
where
18321829
Self: Sized,
18331830
Fold: FnMut(Acc, Self::Item) -> R,
18341831
R: Try<Ok = Acc>,
18351832
{
1836-
fn check<'a, B, T, Acc, R: Try<Ok = Acc>>(
1837-
flag: &'a mut bool,
1838-
p: &'a mut impl FnMut(T) -> Option<B>,
1839-
mut fold: impl FnMut(Acc, B) -> R + 'a,
1840-
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> + 'a {
1841-
move |acc, x| match p(x) {
1842-
Some(item) => LoopState::from_try(fold(acc, item)),
1843-
None => {
1844-
*flag = true;
1845-
LoopState::Break(Try::from_ok(acc))
1846-
}
1847-
}
1848-
}
1849-
1850-
if self.finished {
1851-
Try::from_ok(init)
1852-
} else {
1853-
let flag = &mut self.finished;
1854-
let p = &mut self.predicate;
1855-
self.iter.try_fold(init, check(flag, p, fold)).into_try()
1856-
}
1833+
let Self { iter, predicate } = self;
1834+
iter.try_fold(init, |acc, x| match predicate(x) {
1835+
Some(item) => LoopState::from_try(fold(acc, item)),
1836+
None => LoopState::Break(Try::from_ok(acc)),
1837+
})
1838+
.into_try()
18571839
}
18581840
}
18591841

1860-
#[stable(feature = "fused", since = "1.26.0")]
1861-
impl<I, P> FusedIterator for TakeWhile<I, P>
1862-
where
1863-
I: FusedIterator,
1864-
P: FnMut(&I::Item) -> bool,
1865-
{
1866-
}
1867-
18681842
/// An iterator that skips over `n` elements of `iter`.
18691843
///
18701844
/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its

src/libcore/iter/traits/iterator.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -1037,9 +1037,6 @@ pub trait Iterator {
10371037
/// closure on each element of the iterator, and yield elements
10381038
/// while it returns [`Some(_)`][`Some`].
10391039
///
1040-
/// After [`None`] is returned, `map_while()`'s job is over, and the
1041-
/// rest of the elements are ignored.
1042-
///
10431040
/// # Examples
10441041
///
10451042
/// Basic usage:
@@ -1079,15 +1076,14 @@ pub trait Iterator {
10791076
/// #![feature(iter_map_while)]
10801077
/// use std::convert::TryFrom;
10811078
///
1082-
/// let a = [0, -1, 1, -2];
1083-
///
1084-
/// let mut iter = a.iter().map_while(|x| u32::try_from(*x).ok());
1079+
/// let a = [0, 1, 2, -3, 4, 5, -6];
10851080
///
1086-
/// assert_eq!(iter.next(), Some(0u32));
1081+
/// let iter = a.iter().map_while(|x| u32::try_from(*x).ok());
1082+
/// let vec = iter.collect::<Vec<_>>();
10871083
///
1088-
/// // We have more elements that are fit in u32, but since we already
1089-
/// // got a None, map_while() isn't used any more
1090-
/// assert_eq!(iter.next(), None);
1084+
/// // We have more elements which could fit in u32 (4, 5), but `map_while` returned `None` for `-3`
1085+
/// // (as the `predicate` returned `None`) and `collect` stops at the first `None` entcountered.
1086+
/// assert_eq!(vec, vec![0, 1, 2]);
10911087
/// ```
10921088
///
10931089
/// Because `map_while()` needs to look at the value in order to see if it
@@ -1115,8 +1111,13 @@ pub trait Iterator {
11151111
/// The `-3` is no longer there, because it was consumed in order to see if
11161112
/// the iteration should stop, but wasn't placed back into the iterator.
11171113
///
1114+
/// Note that unlike [`take_while`] this iterator is **not** fused.
1115+
/// It is also not specified what this iterator returns after the first` None` is returned.
1116+
/// If you need fused iterator, use [`fuse`].
1117+
///
11181118
/// [`Some`]: ../../std/option/enum.Option.html#variant.Some
11191119
/// [`None`]: ../../std/option/enum.Option.html#variant.None
1120+
/// [`fuse`]: #method.fuse
11201121
#[inline]
11211122
#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
11221123
fn map_while<B, P>(self, predicate: P) -> MapWhile<Self, P>

0 commit comments

Comments
 (0)