about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-03-22 11:57:58 +0000
committerbors <bors@rust-lang.org>2020-03-22 11:57:58 +0000
commit5ae85f43f4eeaf177cd12f47958b7ff62786b612 (patch)
tree6e91c9881063d776b52e05bada95e8acb4139db3 /src/libcore
parent94d43d656665e59abc10c7c22a3194685e7cc605 (diff)
parente964d7180ca4164dfa3d6c6dee6026889c604812 (diff)
downloadrust-5ae85f43f4eeaf177cd12f47958b7ff62786b612.tar.gz
rust-5ae85f43f4eeaf177cd12f47958b7ff62786b612.zip
Auto merge of #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 https://github.com/rust-lang/rust/pull/66577#discussion_r370958025.

This also resolves open questions of the tracking issue (#68537):
- `MapWhile` can't implement both
  + `DoubleEndedIterator` (discussed in https://github.com/rust-lang/rust/pull/66577#discussion_r370947990 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
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/iter/adapters/mod.rs68
-rw-r--r--src/libcore/iter/traits/iterator.rs21
2 files changed, 32 insertions, 57 deletions
diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs
index 3c0ddcb2bc8..6759a6b2d73 100644
--- a/src/libcore/iter/adapters/mod.rs
+++ b/src/libcore/iter/adapters/mod.rs
@@ -1768,6 +1768,14 @@ where
     }
 }
 
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I, P> FusedIterator for TakeWhile<I, P>
+where
+    I: FusedIterator,
+    P: FnMut(&I::Item) -> bool,
+{
+}
+
 /// An iterator that only accepts elements while `predicate` returns `Some(_)`.
 ///
 /// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its
@@ -1780,20 +1788,19 @@ where
 #[derive(Clone)]
 pub struct MapWhile<I, P> {
     iter: I,
-    finished: bool,
     predicate: P,
 }
 
 impl<I, P> MapWhile<I, P> {
     pub(super) fn new(iter: I, predicate: P) -> MapWhile<I, P> {
-        MapWhile { iter, finished: false, predicate }
+        MapWhile { iter, predicate }
     }
 }
 
 #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
 impl<I: fmt::Debug, P> fmt::Debug for MapWhile<I, P> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("MapWhile").field("iter", &self.iter).field("flag", &self.finished).finish()
+        f.debug_struct("MapWhile").field("iter", &self.iter).finish()
     }
 }
 
@@ -1806,65 +1813,32 @@ where
 
     #[inline]
     fn next(&mut self) -> Option<B> {
-        if self.finished {
-            None
-        } else {
-            let x = self.iter.next()?;
-            let ret = (self.predicate)(x);
-            self.finished = ret.is_none();
-            ret
-        }
+        let x = self.iter.next()?;
+        (self.predicate)(x)
     }
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.finished {
-            (0, Some(0))
-        } else {
-            let (_, upper) = self.iter.size_hint();
-            (0, upper) // can't know a lower bound, due to the predicate
-        }
+        let (_, upper) = self.iter.size_hint();
+        (0, upper) // can't know a lower bound, due to the predicate
     }
 
     #[inline]
-    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, mut fold: Fold) -> R
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
         R: Try<Ok = Acc>,
     {
-        fn check<'a, B, T, Acc, R: Try<Ok = Acc>>(
-            flag: &'a mut bool,
-            p: &'a mut impl FnMut(T) -> Option<B>,
-            mut fold: impl FnMut(Acc, B) -> R + 'a,
-        ) -> impl FnMut(Acc, T) -> LoopState<Acc, R> + 'a {
-            move |acc, x| match p(x) {
-                Some(item) => LoopState::from_try(fold(acc, item)),
-                None => {
-                    *flag = true;
-                    LoopState::Break(Try::from_ok(acc))
-                }
-            }
-        }
-
-        if self.finished {
-            Try::from_ok(init)
-        } else {
-            let flag = &mut self.finished;
-            let p = &mut self.predicate;
-            self.iter.try_fold(init, check(flag, p, fold)).into_try()
-        }
+        let Self { iter, predicate } = self;
+        iter.try_fold(init, |acc, x| match predicate(x) {
+            Some(item) => LoopState::from_try(fold(acc, item)),
+            None => LoopState::Break(Try::from_ok(acc)),
+        })
+        .into_try()
     }
 }
 
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I, P> FusedIterator for TakeWhile<I, P>
-where
-    I: FusedIterator,
-    P: FnMut(&I::Item) -> bool,
-{
-}
-
 /// An iterator that skips over `n` elements of `iter`.
 ///
 /// This `struct` is created by the [`skip`] method on [`Iterator`]. See its
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index e2ebef9c6ce..39bd270da86 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -1037,9 +1037,6 @@ pub trait Iterator {
     /// closure on each element of the iterator, and yield elements
     /// while it returns [`Some(_)`][`Some`].
     ///
-    /// After [`None`] is returned, `map_while()`'s job is over, and the
-    /// rest of the elements are ignored.
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1079,15 +1076,14 @@ pub trait Iterator {
     /// #![feature(iter_map_while)]
     /// use std::convert::TryFrom;
     ///
-    /// let a = [0, -1, 1, -2];
-    ///
-    /// let mut iter = a.iter().map_while(|x| u32::try_from(*x).ok());
+    /// let a = [0, 1, 2, -3, 4, 5, -6];
     ///
-    /// assert_eq!(iter.next(), Some(0u32));
+    /// let iter = a.iter().map_while(|x| u32::try_from(*x).ok());
+    /// let vec = iter.collect::<Vec<_>>();
     ///
-    /// // We have more elements that are fit in u32, but since we already
-    /// // got a None, map_while() isn't used any more
-    /// assert_eq!(iter.next(), None);
+    /// // We have more elements which could fit in u32 (4, 5), but `map_while` returned `None` for `-3`
+    /// // (as the `predicate` returned `None`) and `collect` stops at the first `None` entcountered.
+    /// assert_eq!(vec, vec![0, 1, 2]);
     /// ```
     ///
     /// Because `map_while()` needs to look at the value in order to see if it
@@ -1115,8 +1111,13 @@ pub trait Iterator {
     /// The `-3` is no longer there, because it was consumed in order to see if
     /// the iteration should stop, but wasn't placed back into the iterator.
     ///
+    /// Note that unlike [`take_while`] this iterator is **not** fused.
+    /// It is also not specified what this iterator returns after the first` None` is returned.
+    /// If you need fused iterator, use [`fuse`].
+    ///
     /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
     /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`fuse`]: #method.fuse
     #[inline]
     #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
     fn map_while<B, P>(self, predicate: P) -> MapWhile<Self, P>