Skip to content

Commit 30f9939

Browse files
authored
Rollup merge of #148941 - stabilize-map-if, r=jhpratt
stabilize `Peekable::next_if_map` (`#![feature(peekable_next_if_map)]`) # Stabilization report ## Summary `#![feature(peekable_next_if_map)]` is a variation of `next_if` on peekable iterators that can transform the peeked item. This creates a way to take ownership of the next item in an iterator when some condition holds, but put the item back when the condition doesn't hold. This pattern would otherwise have needed unwraps in many cases. [Tracking issue](#143702) ### What is stabilized ```rust impl<I: Iterator> Peekable<I> { pub fn next_if_map<R>( &mut self, f: impl FnOnce(I::Item) -> Result<R, I::Item>, ) -> Option<R> { .. } pub fn next_if_map_mut<R>( &mut self, f: impl FnOnce(&mut I::Item) -> Option<R>, ) -> Option<R> { .. } } ``` Example usage adapted from the ACP: ```rust let mut it = Peekable::new("123".chars()); while let Some(digit) = it.next_if_map(|c| c.to_digit(10).ok_or(c)) { codepoint = codepoint * 10 + digit; } ``` or with `next_if_map_mut`: ```rust let mut it = Peekable::new("123".chars()); while let Some(digit) = iter.next_if_map_mut(|c| c.to_digit(10)) { line_num = line_num * 10 + digit; } ``` Note that the major difference here is that `next_if_map_mut` does not get owned items from the iterator, but mutable references. With that api, the closure can return an `Option` which avoids an `ok_or`. This may require cloning or copying the iterator elements, so if that is expensive, the owned version, `next_if_map`, may be preferable. ### Nightly use At the moment, this feature is barely used in nightly, though I've found multiple good uses for it in my own projects, hence my pushing for stabilization. It makes the kind of patterns used in recursive descent parsing super concise and maybe with its stabilization it will find more use. ### Test coverage Besides a quite comprehensive doctest, this feature is tested (including panicking in the closure) here: https://github.com/rust-lang/rust/blob/c880acdd3171dfafdb55be8cd9822a857e99348d/library/coretests/tests/iter/adapters/peekable.rs#L275-L359 ## History - ACP: rust-lang/libs-team#613 accepted with rust-lang/libs-team#613 (comment) - implementation: #143725 with tests, and no issues reported since july. ## Acknowledgments ACP, implementation and tracking issue for this feature all by @kennytm <3
2 parents 9bc8b40 + dc3786e commit 30f9939

File tree

2 files changed

+2
-6
lines changed

2 files changed

+2
-6
lines changed

‎library/core/src/iter/adapters/peekable.rs‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ impl<I: Iterator> Peekable<I> {
337337
///
338338
/// Parse the leading decimal number from an iterator of characters.
339339
/// ```
340-
/// #![feature(peekable_next_if_map)]
341340
/// let mut iter = "125 GOTO 10".chars().peekable();
342341
/// let mut line_num = 0_u32;
343342
/// while let Some(digit) = iter.next_if_map(|c| c.to_digit(10).ok_or(c)) {
@@ -349,7 +348,6 @@ impl<I: Iterator> Peekable<I> {
349348
///
350349
/// Matching custom types.
351350
/// ```
352-
/// #![feature(peekable_next_if_map)]
353351
///
354352
/// #[derive(Debug, PartialEq, Eq)]
355353
/// enum Node {
@@ -408,7 +406,7 @@ impl<I: Iterator> Peekable<I> {
408406
///# ],
409407
///# )
410408
/// ```
411-
#[unstable(feature = "peekable_next_if_map", issue = "143702")]
409+
#[stable(feature = "peekable_next_if_map", since = "CURRENT_RUSTC_VERSION")]
412410
pub fn next_if_map<R>(&mut self, f: impl FnOnce(I::Item) -> Result<R, I::Item>) -> Option<R> {
413411
let unpeek = if let Some(item) = self.next() {
414412
match f(item) {
@@ -437,7 +435,6 @@ impl<I: Iterator> Peekable<I> {
437435
///
438436
/// Parse the leading decimal number from an iterator of characters.
439437
/// ```
440-
/// #![feature(peekable_next_if_map)]
441438
/// let mut iter = "125 GOTO 10".chars().peekable();
442439
/// let mut line_num = 0_u32;
443440
/// while let Some(digit) = iter.next_if_map_mut(|c| c.to_digit(10)) {
@@ -446,7 +443,7 @@ impl<I: Iterator> Peekable<I> {
446443
/// assert_eq!(line_num, 125);
447444
/// assert_eq!(iter.collect::<String>(), " GOTO 10");
448445
/// ```
449-
#[unstable(feature = "peekable_next_if_map", issue = "143702")]
446+
#[stable(feature = "peekable_next_if_map", since = "CURRENT_RUSTC_VERSION")]
450447
pub fn next_if_map_mut<R>(&mut self, f: impl FnOnce(&mut I::Item) -> Option<R>) -> Option<R> {
451448
let unpeek = if let Some(mut item) = self.next() {
452449
match f(&mut item) {

‎library/coretests/tests/lib.rs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@
9090
#![feature(one_sided_range)]
9191
#![feature(option_reduce)]
9292
#![feature(pattern)]
93-
#![feature(peekable_next_if_map)]
9493
#![feature(pointer_is_aligned_to)]
9594
#![feature(portable_simd)]
9695
#![feature(ptr_metadata)]

0 commit comments

Comments
 (0)