Auto merge of #77491 - lukaslueg:peek_mut, r=m-ou-se

Proposal to add Peekable::peek_mut

A "peekable" iterator has a `peek()`-method which provides an immutable reference to the next item. We currently do not have a method to modify that item, which we could easily add via a `peek_mut()`. See the test for a use-case (alike to my original use case), where a "pristine" iterator is passed on after modifying its state via `peek_mut()`.

If there is interest in this, I can expand on the tests and docs.
This commit is contained in:
bors 2020-11-25 05:10:53 +00:00
commit b387f62d4d
3 changed files with 49 additions and 0 deletions

View file

@ -216,6 +216,43 @@ impl<I: Iterator> Peekable<I> {
self.peeked.get_or_insert_with(|| iter.next()).as_ref()
}
/// Returns a mutable reference to the next() value without advancing the iterator.
///
/// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
/// But if the iteration is over, `None` is returned.
///
/// Because `peek_mut()` returns a reference, and many iterators iterate over
/// references, there can be a possibly confusing situation where the
/// return value is a double reference. You can see this effect in the examples
/// below.
///
/// [`next`]: Iterator::next
///
/// # Examples
///
/// ```
/// #![feature(peekable_peek_mut)]
/// let mut iter = [1, 2, 3].iter().peekable();
///
/// assert_eq!(iter.peek_mut(), Some(&mut &1));
/// assert_eq!(iter.next(), Some(&1));
///
/// // Peek into the iterator and modify the value which will be returned next
/// if let Some(mut p) = iter.peek_mut() {
/// if *p == &2 {
/// *p = &5;
/// }
/// }
///
/// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]);
/// ```
#[inline]
#[unstable(feature = "peekable_peek_mut", issue = "78302")]
pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
let iter = &mut self.iter;
self.peeked.get_or_insert_with(|| iter.next()).as_mut()
}
/// Consume and return the next value of this iterator if a condition is true.
///
/// If `func` returns `true` for the next value of this iterator, consume and return it.

View file

@ -1134,6 +1134,17 @@ fn test_iterator_peekable_next_if_eq() {
assert_eq!(it.next_if_eq(""), None);
}
#[test]
fn test_iterator_peekable_mut() {
let mut it = vec![1, 2, 3].into_iter().peekable();
if let Some(p) = it.peek_mut() {
if *p == 1 {
*p = 5;
}
}
assert_eq!(it.collect::<Vec<_>>(), vec![5, 2, 3]);
}
/// This is an iterator that follows the Iterator contract,
/// but it is not fused. After having returned None once, it will start
/// producing elements if .next() is called again.

View file

@ -56,6 +56,7 @@
#![feature(unwrap_infallible)]
#![feature(option_unwrap_none)]
#![feature(peekable_next_if)]
#![feature(peekable_peek_mut)]
#![feature(partition_point)]
#![feature(once_cell)]
#![feature(unsafe_block_in_unsafe_fn)]