-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Add PeekableIterator trait as an experiment #95195
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
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/// An iterator whose elements may be checked without advancing the iterator. | ||
/// | ||
/// In general, many [`Iterator`]s are able to "peek" their next element, | ||
/// showing what would be returned by a call to `next` without advancing their | ||
/// internal state. If these iterators do not offer such functionality, it can | ||
/// be manually added to an iterator using the [`peekable`] method. | ||
/// | ||
/// In most cases, calling [`peekable`] on a [`PeekableIterator`] shouldn't | ||
/// noticeably affect functionality, however, it's worth pointing out a few | ||
/// differences between [`peekable`] and [`PeekableIterator`]: | ||
/// | ||
/// * Stateful iterators like those using [`inspect`](Iterator::inspect) will | ||
/// eagerly evaluate when peeked by a [`peekable`] wrapper, but may do so | ||
/// lazily with a custom [`PeekableIterator`] implementation. | ||
/// * The [`peekable`] wrapper will incur a small performance penalty for | ||
/// [`next`] and [`next_back`], but [`PeekableIterator`] implementations | ||
/// incur no such penalty. | ||
/// * The [`peekable`] wrapper will return a reference to its item, whereas | ||
/// [`PeekableIterator`] will return the item directly. | ||
/// | ||
/// Note that this trait is a safe trait and as such does *not* and *cannot* | ||
/// guarantee that the peeked value will be returned in a subsequent call to | ||
/// [`next`], no matter how soon the two are called together. A common | ||
/// example of this is interior mutability; if the interior state of the | ||
/// iterator is mutated between a call to [`peek`] and [`next`], then the | ||
/// values may differ. | ||
/// | ||
/// [`peek`]: Self::peek | ||
/// [`peekable`]: Iterator::peekable | ||
/// [`Peekable`]: super::Peekable | ||
/// [`next`]: Iterator::next | ||
/// [`next_back`]: DoubleEndedIterator::next_back | ||
/// | ||
/// # Examples | ||
/// | ||
/// Basic usage: | ||
/// | ||
/// ``` | ||
/// #![feature(peekable_iterator)] | ||
/// use std::iter::PeekableIterator; | ||
/// | ||
/// // a range knows its current state exactly | ||
/// let five = 0..5; | ||
/// | ||
/// assert_eq!(Some(0), five.peek()); | ||
/// ``` | ||
#[unstable(feature = "peekable_iterator", issue = "none")] | ||
pub trait PeekableIterator: Iterator { | ||
/// Returns a reference to the [`next`] value without advancing the iterator. | ||
/// | ||
/// [`next`]: Iterator::next | ||
/// | ||
/// # Examples | ||
/// | ||
/// Basic usage: | ||
/// | ||
/// ``` | ||
/// #![feature(peekable_iterator)] | ||
/// use std::iter::PeekableIterator; | ||
/// | ||
/// // a finite range knows its current state exactly | ||
/// let five = 0..5; | ||
/// | ||
/// assert_eq!(Some(0), five.peek()); | ||
/// ``` | ||
#[unstable(feature = "peekable_iterator", issue = "none")] | ||
fn peek(&self) -> Option<Self::Item>; | ||
|
||
/// Returns `true` if the [`next`] value is `None`. | ||
/// | ||
/// [`next`]: Iterator::next | ||
/// | ||
/// # Examples | ||
/// | ||
/// Basic usage: | ||
/// | ||
/// ``` | ||
/// #![feature(peekable_iterator)] | ||
/// use std::iter::PeekableIterator; | ||
/// | ||
/// let mut one_element = std::iter::once(0); | ||
/// assert!(one_element.has_next()); | ||
/// | ||
/// assert_eq!(one_element.next(), Some(0)); | ||
/// assert!(!one_element.has_next()); | ||
/// | ||
/// assert_eq!(one_element.next(), None); | ||
/// ``` | ||
#[inline] | ||
#[unstable(feature = "peekable_iterator", issue = "none")] | ||
fn has_next(&self) -> bool { | ||
self.peek().is_some() | ||
} | ||
} | ||
|
||
#[unstable(feature = "peekable_iterator", issue = "none")] | ||
impl<I: PeekableIterator + ?Sized> PeekableIterator for &mut I { | ||
fn peek(&self) -> Option<I::Item> { | ||
(**self).peek() | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Can you say more about why you picked
Option<Item>
instead ofOption<&Item>
here? Especially since that's whatpeek
does https://doc.rust-lang.org/std/iter/struct.Peekable.html#method.peekAnd it'd make sense to me for things like
Repeat
to return a reference to the state, for example.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 big reason is that a majority of iterators are completely impossible to do with that type signature. By-reference and by-mutable-reference iterators over collections would completely break, and that's loads of use cases right there.
At first I did that, then I realised how bad of an idea it would be to do that. Essentially, the use cases that would prefer just storing the next value and then referencing it are covered by peekable, and this covers the ones where that seems suboptimal.
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.
But that leads to some implementations using
clone()
, andhas_next()
just callspeek()
which then clones. That callinghas_next()
might allocate is going to be surprising and certainly more costly thanExactSizeIterator
'sis_empty()
.Edit: Ah, you mention this already in the PR comment.