-
Notifications
You must be signed in to change notification settings - Fork 13.9k
Add PeekableIterator trait
#144935
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
base: master
Are you sure you want to change the base?
Add PeekableIterator trait
#144935
Changes from 14 commits
38e446a
8d2bdb0
ecc7b86
3dd13bc
bf0193c
dc33dd2
5892463
ec565f6
ff668ec
56d74c6
c552fc8
6fc70f2
54ad568
14a6ecd
746c699
2fa7343
a2ce876
bf88550
9e0f1ae
495b775
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 |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| #[unstable(feature = "peekable_iterator", issue = "132973")] | ||
| /// Iterators which inherently support peeking without needing to be wrapped by a `Peekable`. | ||
| pub trait PeekableIterator: Iterator { | ||
| /// Executes the closure with a reference to the `next()` value without advancing the iterator. | ||
| fn peek_with<T>(&mut self, func: impl for<'a> FnOnce(Option<&'a Self::Item>) -> T) -> T; | ||
|
|
||
| /// Executes the closure on the `next()` element without advancing the iterator, or returns `None` if the iterator is exhausted. | ||
| fn peek_map<T>(&mut self, func: impl for<'a> FnOnce(&'a Self::Item) -> T) -> Option<T> { | ||
| self.peek_with(|x| x.map(|y| func(y))) | ||
| } | ||
|
||
|
|
||
| /// Returns the `next()` element if the given predicate holds true. | ||
| fn next_if(&mut self, func: impl FnOnce(&Self::Item) -> bool) -> Option<Self::Item> { | ||
| match self.peek_map(func) { | ||
| Some(true) => self.next(), | ||
| _ => None, | ||
| } | ||
| } | ||
|
|
||
| /// Moves forward and return the `next()` item if it is equal to the expected value. | ||
| fn next_if_eq<T>(&mut self, expected: &T) -> Option<Self::Item> | ||
| where | ||
| Self::Item: PartialEq<T>, | ||
| T: ?Sized, | ||
| { | ||
| self.next_if(|x| x == expected) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -468,6 +468,34 @@ macro_rules! iterator { | |||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| #[unstable(feature = "peekable_iterator", issue = "132973")] | ||||||||||||
| impl<'a, T> PeekableIterator for $name<'a, T> { | ||||||||||||
| fn peek_with<U>(&mut self, func: impl for<'b> FnOnce(Option<&'b Self::Item>) -> U) -> U { | ||||||||||||
| let ptr = self.ptr; | ||||||||||||
| let end_or_len = self.end_or_len; | ||||||||||||
|
|
||||||||||||
| // SAFETY: See inner comments. | ||||||||||||
| unsafe { | ||||||||||||
| if T::IS_ZST { | ||||||||||||
| let len = end_or_len.addr(); | ||||||||||||
| if len == 0 { | ||||||||||||
| return func(None); | ||||||||||||
| } | ||||||||||||
| } else { | ||||||||||||
| // SAFETY: by type invariant, the `end_or_len` field is always | ||||||||||||
| // non-null for a non-ZST pointee. (This transmute ensures we | ||||||||||||
| // get `!nonnull` metadata on the load of the field.) | ||||||||||||
| if ptr == crate::intrinsics::transmute::<$ptr, NonNull<T>>(end_or_len) { | ||||||||||||
|
||||||||||||
| // SAFETY: by type invariant, the `end_or_len` field is always | |
| // non-null for a non-ZST pointee. (This transmute ensures we | |
| // get `!nonnull` metadata on the load of the field.) | |
| if ptr == crate::intrinsics::transmute::<$ptr, NonNull<T>>(end_or_len) { | |
| if ptr.as_ptr() == end_or_len { |
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.
Hmm, I was not able to write it this way as Rust determines the types differ in their mutability. In general, this code was based on the next() method generic over both Iter and IterMut
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.
What exactly was the error? Seems possible to resolve by adding a $as_ptr metavar that is either as_ptr or as_mut_ptr depending on which one is being implemented (like into_ref).
next is a bit magical, others should try to be simpler if possible. cloning and advancing should be fine, it's cheap.
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.
Cloning actually wouldn't work for IterMut since it doesn't implement it. But that actually brings up a good point; the safety comments need to say why it is sound to hand out a&mut T.
Uh oh!
There was an error while loading. Please reload this page.