Skip to content

Commit 822ad87

Browse files

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

src/libcore/iter/adapters/mod.rs

+63
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,69 @@ impl<I: Iterator> Peekable<I> {
15741574
let iter = &mut self.iter;
15751575
self.peeked.get_or_insert_with(|| iter.next()).as_ref()
15761576
}
1577+
1578+
/// Consume the next value of this iterator if a condition is true.
1579+
///
1580+
/// If `func` returns `true` for the next value of this iterator, consume and return it.
1581+
/// Otherwise, return `None`.
1582+
///
1583+
/// # Examples
1584+
/// Consume a number if it's equal to 0.
1585+
/// ```
1586+
/// #![feature(peekable_next_if)]
1587+
/// let mut iter = (0..5).peekable();
1588+
/// // The first item of the iterator is 0; consume it.
1589+
/// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
1590+
/// // The next item returned is now 1, so `consume` will return `false`.
1591+
/// assert_eq!(iter.next_if(|&x| x == 0), None);
1592+
/// // `next_if` saves the value of the next item if it was not equal to `expected`.
1593+
/// assert_eq!(iter.next(), Some(1));
1594+
/// ```
1595+
///
1596+
/// Consume any number less than 10.
1597+
/// ```
1598+
/// #![feature(peekable_next_if)]
1599+
/// let mut iter = (1..20).peekable();
1600+
/// // Consume all numbers less than 10
1601+
/// while iter.next_if(|&x| x < 10).is_some() {}
1602+
/// // The next value returned will be 10
1603+
/// assert_eq!(iter.next(), Some(10));
1604+
/// ```
1605+
#[unstable(feature = "peekable_next_if", issue = "72480")]
1606+
pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
1607+
match self.next() {
1608+
Some(matched) if func(&matched) => Some(matched),
1609+
other => {
1610+
// Since we called `self.next()`, we consumed `self.peeked`.
1611+
assert!(self.peeked.is_none());
1612+
self.peeked = Some(other);
1613+
None
1614+
}
1615+
}
1616+
}
1617+
1618+
/// Consume the next item if it is equal to `expected`.
1619+
///
1620+
/// # Example
1621+
/// Consume a number if it's equal to 0.
1622+
/// ```
1623+
/// #![feature(peekable_next_if)]
1624+
/// let mut iter = (0..5).peekable();
1625+
/// // The first item of the iterator is 0; consume it.
1626+
/// assert_eq!(iter.next_if_eq(&0), Some(0));
1627+
/// // The next item returned is now 1, so `consume` will return `false`.
1628+
/// assert_eq!(iter.next_if_eq(&0), None);
1629+
/// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
1630+
/// assert_eq!(iter.next(), Some(1));
1631+
/// ```
1632+
#[unstable(feature = "peekable_next_if", issue = "72480")]
1633+
pub fn next_if_eq<R>(&mut self, expected: &R) -> Option<I::Item>
1634+
where
1635+
R: ?Sized,
1636+
I::Item: PartialEq<R>,
1637+
{
1638+
self.next_if(|next| next == expected)
1639+
}
15771640
}
15781641

15791642
/// An iterator that rejects elements while `predicate` returns `true`.

src/libcore/tests/iter.rs

+24
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,30 @@ fn test_iterator_peekable_rfold() {
813813
assert_eq!(i, xs.len());
814814
}
815815

816+
#[test]
817+
fn test_iterator_peekable_next_if_eq() {
818+
// first, try on references
819+
let xs = vec!["Heart", "of", "Gold"];
820+
let mut it = xs.into_iter().peekable();
821+
// try before `peek()`
822+
assert_eq!(it.next_if_eq(&"trillian"), None);
823+
assert_eq!(it.next_if_eq(&"Heart"), Some("Heart"));
824+
// try after peek()
825+
assert_eq!(it.peek(), Some(&"of"));
826+
assert_eq!(it.next_if_eq(&"of"), Some("of"));
827+
assert_eq!(it.next_if_eq(&"zaphod"), None);
828+
// make sure `next()` still behaves
829+
assert_eq!(it.next(), Some("Gold"));
830+
831+
// make sure comparison works for owned values
832+
let xs = vec![String::from("Ludicrous"), "speed".into()];
833+
let mut it = xs.into_iter().peekable();
834+
// make sure basic functionality works
835+
assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into()));
836+
assert_eq!(it.next_if_eq("speed"), Some("speed".into()));
837+
assert_eq!(it.next_if_eq(""), None);
838+
}
839+
816840
/// This is an iterator that follows the Iterator contract,
817841
/// but it is not fused. After having returned None once, it will start
818842
/// producing elements if .next() is called again.

src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#![feature(leading_trailing_ones)]
4545
#![feature(const_forget)]
4646
#![feature(option_unwrap_none)]
47+
#![feature(peekable_next_if)]
4748

4849
extern crate test;
4950

0 commit comments

Comments
 (0)