Skip to content

Commit 5ab3c2f

Browse files
committed
Add PeekableIterator trait as an experiment
1 parent 3c17c84 commit 5ab3c2f

File tree

14 files changed

+251
-12
lines changed

14 files changed

+251
-12
lines changed

library/core/src/iter/adapters/copied.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::iter::adapters::{
22
zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
33
};
4-
use crate::iter::{FusedIterator, TrustedLen};
4+
use crate::iter::{FusedIterator, PeekableIterator, TrustedLen};
55
use crate::ops::Try;
66

77
/// An iterator that copies the elements of an underlying iterator.
@@ -139,6 +139,17 @@ where
139139
}
140140
}
141141

142+
#[unstable(feature = "peekable_iterator", issue = "none")]
143+
impl<'a, I, T: 'a> PeekableIterator for Copied<I>
144+
where
145+
I: PeekableIterator<Item = &'a T>,
146+
T: Copy,
147+
{
148+
fn peek(&self) -> Option<T> {
149+
self.it.peek().map(|x| *x)
150+
}
151+
}
152+
142153
#[stable(feature = "iter_copied", since = "1.36.0")]
143154
impl<'a, I, T: 'a> FusedIterator for Copied<I>
144155
where

library/core/src/iter/adapters/cycle.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::{iter::FusedIterator, ops::Try};
1+
use crate::{
2+
iter::{FusedIterator, PeekableIterator},
3+
ops::Try,
4+
};
25

36
/// An iterator that repeats endlessly.
47
///
@@ -104,5 +107,15 @@ where
104107
// and we can't do anything better than the default.
105108
}
106109

110+
#[unstable(feature = "peekable_iterator", issue = "none")]
111+
impl<I> PeekableIterator for Cycle<I>
112+
where
113+
I: Clone + PeekableIterator,
114+
{
115+
fn peek(&self) -> Option<I::Item> {
116+
self.iter.peek().or_else(|| self.orig.peek())
117+
}
118+
}
119+
107120
#[stable(feature = "fused", since = "1.26.0")]
108121
impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}

library/core/src/iter/adapters/enumerate.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::iter::adapters::{
22
zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
33
};
4-
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
4+
use crate::iter::{FusedIterator, InPlaceIterable, PeekableIterator, TrustedLen};
55
use crate::ops::Try;
66

77
/// An iterator that yields the current count and the element during iteration.
@@ -229,6 +229,16 @@ where
229229
}
230230
}
231231

232+
#[stable(feature = "rust1", since = "1.0.0")]
233+
impl<I> PeekableIterator for Enumerate<I>
234+
where
235+
I: PeekableIterator,
236+
{
237+
fn peek(&self) -> Option<(usize, I::Item)> {
238+
self.iter.peek().map(|x| (self.count, x))
239+
}
240+
}
241+
232242
#[doc(hidden)]
233243
#[unstable(feature = "trusted_random_access", issue = "none")]
234244
unsafe impl<I> TrustedRandomAccess for Enumerate<I> where I: TrustedRandomAccess {}

library/core/src/iter/adapters/fuse.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::intrinsics;
22
use crate::iter::adapters::zip::try_get_unchecked;
33
use crate::iter::{
4-
DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess,
5-
TrustedRandomAccessNoCoerce,
4+
DoubleEndedIterator, ExactSizeIterator, FusedIterator, PeekableIterator, TrustedLen,
5+
TrustedRandomAccess, TrustedRandomAccessNoCoerce,
66
};
77
use crate::ops::Try;
88

@@ -26,6 +26,16 @@ impl<I> Fuse<I> {
2626
}
2727
}
2828

29+
#[unstable(feature = "peekable_iterator", issue = "none")]
30+
impl<I> PeekableIterator for Fuse<I>
31+
where
32+
I: PeekableIterator,
33+
{
34+
fn peek(&self) -> Option<I::Item> {
35+
self.iter.as_ref().and_then(|iter| iter.peek())
36+
}
37+
}
38+
2939
#[stable(feature = "fused", since = "1.26.0")]
3040
impl<I> FusedIterator for Fuse<I> where I: Iterator {}
3141

library/core/src/iter/adapters/inspect.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::fmt;
2-
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
2+
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, PeekableIterator};
33
use crate::ops::Try;
44

55
/// An iterator that calls a function with a reference to each element before
@@ -145,6 +145,16 @@ where
145145
}
146146
}
147147

148+
#[unstable(feature = "peekable_iterator", issue = "none")]
149+
impl<I: PeekableIterator, F> PeekableIterator for Inspect<I, F>
150+
where
151+
F: FnMut(&I::Item),
152+
{
153+
fn peek(&self) -> Option<I::Item> {
154+
self.iter.peek()
155+
}
156+
}
157+
148158
#[stable(feature = "fused", since = "1.26.0")]
149159
impl<I: FusedIterator, F> FusedIterator for Inspect<I, F> where F: FnMut(&I::Item) {}
150160

library/core/src/iter/adapters/take.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::cmp;
2-
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
2+
use crate::iter::{
3+
adapters::SourceIter, FusedIterator, InPlaceIterable, PeekableIterator, TrustedLen,
4+
};
35
use crate::ops::{ControlFlow, Try};
46

57
/// An iterator that only iterates over the first `n` iterations of `iter`.
@@ -237,6 +239,16 @@ where
237239
#[stable(feature = "rust1", since = "1.0.0")]
238240
impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
239241

242+
#[unstable(feature = "peekable_iterator", issue = "none")]
243+
impl<I> PeekableIterator for Take<I>
244+
where
245+
I: PeekableIterator,
246+
{
247+
fn peek(&self) -> Option<I::Item> {
248+
if self.n == 0 { None } else { self.iter.peek() }
249+
}
250+
}
251+
240252
#[stable(feature = "fused", since = "1.26.0")]
241253
impl<I> FusedIterator for Take<I> where I: FusedIterator {}
242254

library/core/src/iter/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ pub use self::sources::{successors, Successors};
382382
pub use self::traits::FusedIterator;
383383
#[unstable(issue = "none", feature = "inplace_iteration")]
384384
pub use self::traits::InPlaceIterable;
385+
#[unstable(feature = "peekable_iterator", issue = "none")]
386+
pub use self::traits::PeekableIterator;
385387
#[unstable(feature = "trusted_len", issue = "37572")]
386388
pub use self::traits::TrustedLen;
387389
#[unstable(feature = "trusted_step", issue = "85731")]

library/core/src/iter/range.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use crate::mem;
44
use crate::ops::{self, Try};
55

66
use super::{
7-
FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, TrustedStep,
7+
FusedIterator, PeekableIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
8+
TrustedStep,
89
};
910

1011
// Safety: All invariants are upheld.
@@ -765,6 +766,13 @@ impl<A: Step> Iterator for ops::Range<A> {
765766
}
766767
}
767768

769+
#[unstable(feature = "peekable_iterator", issue = "none")]
770+
impl<A: Step> PeekableIterator for ops::Range<A> {
771+
fn peek(&self) -> Option<A> {
772+
if self.start < self.end { Some(self.start.clone()) } else { None }
773+
}
774+
}
775+
768776
// These macros generate `ExactSizeIterator` impls for various range types.
769777
//
770778
// * `ExactSizeIterator::len` is required to always return an exact `usize`,
@@ -879,6 +887,13 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
879887
}
880888
}
881889

890+
#[unstable(feature = "peekable_iterator", issue = "none")]
891+
impl<A: Step> PeekableIterator for ops::RangeFrom<A> {
892+
fn peek(&self) -> Option<A> {
893+
Some(self.start.clone())
894+
}
895+
}
896+
882897
// Safety: See above implementation for `ops::Range<A>`
883898
#[unstable(feature = "trusted_len", issue = "37572")]
884899
unsafe impl<A: TrustedStep> TrustedLen for ops::RangeFrom<A> {}
@@ -1186,6 +1201,13 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
11861201
}
11871202
}
11881203

1204+
#[unstable(feature = "peekable_iterator", issue = "none")]
1205+
impl<A: Step> PeekableIterator for ops::RangeInclusive<A> {
1206+
fn peek(&self) -> Option<A> {
1207+
if self.is_empty() { None } else { Some(self.start.clone()) }
1208+
}
1209+
}
1210+
11891211
#[stable(feature = "inclusive_range", since = "1.26.0")]
11901212
impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
11911213
#[inline]

library/core/src/iter/sources/empty.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::fmt;
2-
use crate::iter::{FusedIterator, TrustedLen};
2+
use crate::iter::{FusedIterator, PeekableIterator, TrustedLen};
33
use crate::marker;
44

55
/// Creates an iterator that yields nothing.
@@ -68,6 +68,13 @@ impl<T> ExactSizeIterator for Empty<T> {
6868
}
6969
}
7070

71+
#[unstable(feature = "peekable_iterator", issue = "none")]
72+
impl<T> PeekableIterator for Empty<T> {
73+
fn peek(&self) -> Option<T> {
74+
None
75+
}
76+
}
77+
7178
#[unstable(feature = "trusted_len", issue = "37572")]
7279
unsafe impl<T> TrustedLen for Empty<T> {}
7380

library/core/src/iter/sources/once.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::iter::{FusedIterator, TrustedLen};
1+
use crate::iter::{FusedIterator, PeekableIterator, TrustedLen};
22

33
/// Creates an iterator that yields an element exactly once.
44
///
@@ -92,6 +92,13 @@ impl<T> ExactSizeIterator for Once<T> {
9292
}
9393
}
9494

95+
#[unstable(feature = "peekable_iterator", issue = "none")]
96+
impl<T: Clone> PeekableIterator for Once<T> {
97+
fn peek(&self) -> Option<T> {
98+
self.inner.peek()
99+
}
100+
}
101+
95102
#[unstable(feature = "trusted_len", issue = "37572")]
96103
unsafe impl<T> TrustedLen for Once<T> {}
97104

library/core/src/iter/sources/repeat.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::iter::{FusedIterator, TrustedLen};
1+
use crate::iter::{FusedIterator, PeekableIterator, TrustedLen};
22

33
/// Creates a new iterator that endlessly repeats a single element.
44
///
@@ -122,6 +122,13 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
122122
}
123123
}
124124

125+
#[unstable(feature = "peekable_iterator", issue = "none")]
126+
impl<A: Copy> PeekableIterator for Repeat<A> {
127+
fn peek(&self) -> Option<A> {
128+
Some(self.element)
129+
}
130+
}
131+
125132
#[stable(feature = "fused", since = "1.26.0")]
126133
impl<A: Clone> FusedIterator for Repeat<A> {}
127134

library/core/src/iter/traits/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod double_ended;
44
mod exact_size;
55
mod iterator;
66
mod marker;
7+
mod peekable;
78

89
#[stable(feature = "rust1", since = "1.0.0")]
910
pub use self::{
@@ -19,3 +20,5 @@ pub use self::{
1920
pub use self::marker::InPlaceIterable;
2021
#[unstable(feature = "trusted_step", issue = "85731")]
2122
pub use self::marker::TrustedStep;
23+
#[unstable(feature = "peekable_iterator", issue = "none")]
24+
pub use self::peekable::PeekableIterator;
+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/// An iterator whose elements may be checked without advancing the iterator.
2+
///
3+
/// In general, many [`Iterator`]s are able to "peek" their next element,
4+
/// showing what would be returned by a call to `next` without advancing their
5+
/// internal state. If these iterators do not offer such functionality, it can
6+
/// be manually added to an iterator using the [`peekable`] method.
7+
///
8+
/// In most cases, calling [`peekable`] on a [`PeekableIterator`] shouldn't
9+
/// noticeably affect functionality, however, it's worth pointing out a few
10+
/// differences between [`peekable`] and [`PeekableIterator`]:
11+
///
12+
/// * Stateful iterators like those using [`inspect`](Iterator::inspect) will
13+
/// eagerly evaluate when peeked by a [`peekable`] wrapper, but may do so
14+
/// lazily with a custom [`PeekableIterator`] implementation.
15+
/// * The [`peekable`] wrapper will incur a small performance penalty for
16+
/// [`next`] and [`next_back`], but [`PeekableIterator`] implementations
17+
/// incur no such penalty.
18+
/// * The [`peekable`] wrapper will return a reference to its item, whereas
19+
/// [`PeekableIterator`] will return the item directly.
20+
///
21+
/// Note that this trait is a safe trait and as such does *not* and *cannot*
22+
/// guarantee that the peeked value will be returned in a subsequent call to
23+
/// [`next`], no matter how soon the two are called together. A common
24+
/// example of this is interior mutability; if the interior state of the
25+
/// iterator is mutated between a call to [`peek`] and [`next`], then the
26+
/// values may differ.
27+
///
28+
/// [`peek`]: Self::peek
29+
/// [`peekable`]: Iterator::peekable
30+
/// [`Peekable`]: super::Peekable
31+
/// [`next`]: Iterator::next
32+
/// [`next_back`]: DoubleEndedIterator::next_back
33+
///
34+
/// # Examples
35+
///
36+
/// Basic usage:
37+
///
38+
/// ```
39+
/// #![feature(peekable_iterator)]
40+
/// use std::iter::PeekableIterator;
41+
///
42+
/// // a range knows its current state exactly
43+
/// let five = 0..5;
44+
///
45+
/// assert_eq!(Some(0), five.peek());
46+
/// ```
47+
#[unstable(feature = "peekable_iterator", issue = "none")]
48+
pub trait PeekableIterator: Iterator {
49+
/// Returns a reference to the [`next`] value without advancing the iterator.
50+
///
51+
/// [`next`]: Iterator::next
52+
///
53+
/// # Examples
54+
///
55+
/// Basic usage:
56+
///
57+
/// ```
58+
/// #![feature(peekable_iterator)]
59+
/// use std::iter::PeekableIterator;
60+
///
61+
/// // a finite range knows its current state exactly
62+
/// let five = 0..5;
63+
///
64+
/// assert_eq!(Some(0), five.peek());
65+
/// ```
66+
#[unstable(feature = "peekable_iterator", issue = "none")]
67+
fn peek(&self) -> Option<Self::Item>;
68+
69+
/// Returns `true` if the [`next`] value is `None`.
70+
///
71+
/// [`next`]: Iterator::next
72+
///
73+
/// # Examples
74+
///
75+
/// Basic usage:
76+
///
77+
/// ```
78+
/// #![feature(peekable_iterator)]
79+
/// use std::iter::PeekableIterator;
80+
///
81+
/// let mut one_element = std::iter::once(0);
82+
/// assert!(one_element.has_next());
83+
///
84+
/// assert_eq!(one_element.next(), Some(0));
85+
/// assert!(!one_element.has_next());
86+
///
87+
/// assert_eq!(one_element.next(), None);
88+
/// ```
89+
#[inline]
90+
#[unstable(feature = "peekable_iterator", issue = "none")]
91+
fn has_next(&self) -> bool {
92+
self.peek().is_some()
93+
}
94+
}
95+
96+
#[unstable(feature = "peekable_iterator", issue = "none")]
97+
impl<I: PeekableIterator + ?Sized> PeekableIterator for &mut I {
98+
fn peek(&self) -> Option<I::Item> {
99+
(**self).peek()
100+
}
101+
}

0 commit comments

Comments
 (0)