-
Notifications
You must be signed in to change notification settings - Fork 14k
Add Iterator::map_while
#66577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Iterator::map_while
#66577
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1752,6 +1752,95 @@ where | |
| } | ||
| } | ||
|
|
||
| /// An iterator that only accepts elements while `predicate` returns `Some(_)`. | ||
| /// | ||
| /// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its | ||
| /// documentation for more. | ||
| /// | ||
| /// [`map_while`]: trait.Iterator.html#method.map_while | ||
| /// [`Iterator`]: trait.Iterator.html | ||
| #[must_use = "iterators are lazy and do nothing unless consumed"] | ||
| #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] | ||
| #[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 } | ||
| } | ||
| } | ||
|
|
||
| #[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() | ||
|
||
| } | ||
| } | ||
|
|
||
| #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] | ||
| impl<B, I: Iterator, P> Iterator for MapWhile<I, P> | ||
WaffleLapkin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| where | ||
| P: FnMut(I::Item) -> Option<B>, | ||
| { | ||
| type Item = B; | ||
|
|
||
| #[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 | ||
| } | ||
| } | ||
|
|
||
| #[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 | ||
| } | ||
| } | ||
|
|
||
| #[inline] | ||
| fn try_fold<Acc, Fold, R>(&mut self, init: Acc, 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() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[stable(feature = "fused", since = "1.26.0")] | ||
| impl<I, P> FusedIterator for TakeWhile<I, P> | ||
WaffleLapkin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| where | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the
finishedfield needed? It looks like it's only used to makeMapWhilefused but that seems unnecessary when you can instead just call.fuse()if needed.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole point of the
MapWhileis that it stops on firstNonejust likeTakeWhilestops on firstfalseThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It stops by having
.next()returnNone. Thefinishedfield isn't needed to do that. After then it doesn't matter what.next()returns unless the iterator implementsFusedIteratorwhichMapWhiledoesn't.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I first thought it was to improve the upper bound of
size_hint, but it also doesn't matter what that method returns once the iterator has been exhausted. So I suppose you're right. We probably can't remove it fromTakeWhilethough, since it already implementsFusedIterator.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be a bit confusing, so if we do remove
finishedflag, then I think we need to mention it in the docs