- Notifications
You must be signed in to change notification settings - Fork 14k
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: main
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.