Skip to content
Open
Show file tree
Hide file tree
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
9 changes: 8 additions & 1 deletion library/core/src/array/iter.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Defines the `IntoIter` owned iterator for arrays.

use crate::intrinsics::transmute_unchecked;
use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce};
use crate::iter::{FusedIterator, PeekableIterator, TrustedLen, TrustedRandomAccessNoCoerce};
use crate::mem::MaybeUninit;
use crate::num::NonZero;
use crate::ops::{IndexRange, Range, Try};
Expand Down Expand Up @@ -350,6 +350,13 @@ impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}

#[unstable(feature = "peekable_iterator", issue = "132973")]
impl<T, const N: usize> PeekableIterator for IntoIter<T, N> {
fn peek_with<U>(&mut self, func: impl for<'b> FnOnce(Option<&'b Self::Item>) -> U) -> U {
self.unsize_mut().peek_with(func)
}
}

#[doc(hidden)]
#[unstable(issue = "none", feature = "std_internals")]
#[rustc_unsafe_specialization_marker]
Expand Down
8 changes: 8 additions & 0 deletions library/core/src/array/iter/iter_inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ impl<T> PolymorphicIter<[MaybeUninit<T>]> {
})
}

#[inline]
pub(super) fn peek_with<U>(&self, func: impl for<'b> FnOnce(Option<&'b T>) -> U) -> U {
func(self.alive.clone().next().map(|idx| {
// SAFETY: `idx` is in self.alive range
unsafe { self.data.get_unchecked(idx).assume_init_ref() }
}))
}

#[inline]
pub(super) fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
Expand Down
10 changes: 9 additions & 1 deletion library/core/src/iter/adapters/peekable.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::iter::adapters::SourceIter;
use crate::iter::{FusedIterator, TrustedLen};
use crate::iter::{FusedIterator, PeekableIterator, TrustedLen};
use crate::ops::{ControlFlow, Try};

/// An iterator with a `peek()` that returns an optional reference to the next
Expand Down Expand Up @@ -322,6 +322,14 @@ impl<I: Iterator> Peekable<I> {
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}

#[unstable(feature = "peekable_iterator", issue = "132973")]
impl<I: Iterator> PeekableIterator for Peekable<I> {
fn peek_with<T>(&mut self, func: impl for<'a> FnOnce(Option<&'a Self::Item>) -> T) -> T {
let tmp = self.peek();
func(tmp)
}
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: Iterator> SourceIter for Peekable<I>
where
Expand Down
2 changes: 2 additions & 0 deletions library/core/src/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,8 @@ pub use self::traits::FusedIterator;
pub use self::traits::InPlaceIterable;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::traits::Iterator;
#[unstable(feature = "peekable_iterator", issue = "132973")]
pub use self::traits::PeekableIterator;
#[unstable(issue = "none", feature = "trusted_fused")]
pub use self::traits::TrustedFused;
#[unstable(feature = "trusted_len", issue = "37572")]
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/iter/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod double_ended;
mod exact_size;
mod iterator;
mod marker;
mod peekable;
mod unchecked_iterator;

#[unstable(issue = "none", feature = "inplace_iteration")]
Expand All @@ -12,6 +13,8 @@ pub use self::marker::InPlaceIterable;
pub use self::marker::TrustedFused;
#[unstable(feature = "trusted_step", issue = "85731")]
pub use self::marker::TrustedStep;
#[unstable(feature = "peekable_iterator", issue = "132973")]
pub use self::peekable::PeekableIterator;
pub(crate) use self::unchecked_iterator::UncheckedIterator;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::{
Expand Down
77 changes: 77 additions & 0 deletions library/core/src/iter/traits/peekable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#[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.
///
/// # Examples
///
/// Basic usage:
/// ```
/// #![feature(peekable_iterator)]
/// use std::iter::PeekableIterator;
///
/// let mut vals = [0, 1, 2].into_iter();
///
/// assert_eq!(vals.peek_with(|x| x.copied()), Some(0));
/// // element is not consumed
/// assert_eq!(vals.next(), Some(0));
///
/// // examine the pending element
/// assert_eq!(vals.peek_with(|x| x.copied()), Some(1));
/// assert_eq!(vals.next(), Some(1));
///
/// // determine if the iterator has an element without advancing
/// assert_eq!(vals.peek_with(|x| x.is_some()), false);
/// assert_eq!(vals.next(), Some(2));
///
/// // exhausted iterator
/// assert_eq!(vals.next(), None);
/// assert_eq!(vals.peek_with(|x| x.copied()), None);
/// ```
fn peek_with<T>(&mut self, func: impl for<'a> FnOnce(Option<&'a Self::Item>) -> T) -> T;

/// Returns the `next()` element if the given predicate holds true.
///
/// # Examples
///
/// Basic usage:
/// ```
/// #![feature(peekable_iterator)]
/// use std::iter::PeekableIterator;
/// fn parse_number(s: &str) -> u32 {
/// let mut c = s.chars();
///
/// let base = if c.next_if_eq(&"0").is_some() {
/// match c.next_if(|c| "oxb".contains(c)) {
/// Some("x") => 16,
/// Some("b") => 2,
/// _ => 8
/// }
/// } else {
/// 10
/// }
///
/// u32::from_str_radix(c.as_str(), base).unwrap()
/// }
///
/// assert_eq!(parse_number("055"), 45);
/// assert_eq!(parse_number("0o42"), 34);
/// assert_eq!(parse_number("0x11"), 17);
/// ```
///
fn next_if(&mut self, func: impl FnOnce(&Self::Item) -> bool) -> Option<Self::Item> {
match self.peek_with(|x| x.map(|y| func(y))) {
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)
}
}
3 changes: 2 additions & 1 deletion library/core/src/slice/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ mod macros;
use super::{from_raw_parts, from_raw_parts_mut};
use crate::hint::assert_unchecked;
use crate::iter::{
FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, UncheckedIterator,
FusedIterator, PeekableIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
UncheckedIterator,
};
use crate::marker::PhantomData;
use crate::mem::{self, SizedTypeProperties};
Expand Down
15 changes: 15 additions & 0 deletions library/core/src/slice/iter/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,21 @@ 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 {

if len!(self) == 0 {
func(None)
} else {
// SAFETY: Element within bounds as len > 0.
// The reference is dropped after the closure completes
// and can not outlive the mutable borrow of self.
let tmp = unsafe { & $( $mut_ )? *self.ptr.as_ptr() };
func(Some(tmp).as_ref())
}
}
}
#[stable(feature = "default_iters", since = "1.70.0")]
impl<T> Default for $name<'_, T> {
/// Creates an empty slice iterator.
Expand Down
12 changes: 10 additions & 2 deletions library/core/src/str/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use super::{
};
use crate::fmt::{self, Write};
use crate::iter::{
Chain, Copied, Filter, FlatMap, Flatten, FusedIterator, Map, TrustedLen, TrustedRandomAccess,
TrustedRandomAccessNoCoerce,
Chain, Copied, Filter, FlatMap, Flatten, FusedIterator, Map, PeekableIterator, TrustedLen,
TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::num::NonZero;
use crate::ops::Try;
Expand Down Expand Up @@ -132,6 +132,14 @@ impl<'a> DoubleEndedIterator for Chars<'a> {
}
}

#[unstable(feature = "peekable_iterator", issue = "132973")]
impl<'a> PeekableIterator for Chars<'a> {
fn peek_with<T>(&mut self, func: impl for<'b> FnOnce(Option<&'b Self::Item>) -> T) -> T {
let tmp = self.clone().next();
func(tmp.as_ref())
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for Chars<'_> {}

Expand Down
Loading