@@ -317,6 +317,108 @@ impl<I: Iterator> Peekable<I> {
317317 {
318318 self . next_if ( |next| next == expected)
319319 }
320+
321+ /// Consumes the next value of this iterator and applies a function `f` on it,
322+ /// returning the result if the closure returns `Ok`.
323+ ///
324+ /// Otherwise if the closure returns `Err` the value is put back for the next iteration.
325+ ///
326+ /// The content of the `Err` variant is typically the original value of the closure,
327+ /// but this is not required. If a different value is returned,
328+ /// the next `peek()` or `next()` call will result in this new value.
329+ /// This is similar to modifying the output of `peek_mut()`.
330+ ///
331+ /// If the closure panics, the next value will always be consumed and dropped
332+ /// even if the panic is caught, because the closure never returned an `Err` value to put back.
333+ ///
334+ /// # Examples
335+ ///
336+ /// Parse the leading decimal number from an iterator of characters.
337+ /// ```
338+ /// #![feature(peekable_next_if_map)]
339+ /// let mut iter = "125 GOTO 10".chars().peekable();
340+ /// let mut line_num = 0_u32;
341+ /// while let Some(digit) = iter.next_if_map(|c| c.to_digit(10).ok_or(c)) {
342+ /// line_num = line_num * 10 + digit;
343+ /// }
344+ /// assert_eq!(line_num, 125);
345+ /// assert_eq!(iter.collect::<String>(), " GOTO 10");
346+ /// ```
347+ ///
348+ /// Matching custom types.
349+ /// ```
350+ /// #![feature(peekable_next_if_map)]
351+ ///
352+ /// #[derive(Debug, PartialEq, Eq)]
353+ /// enum Node {
354+ /// Comment(String),
355+ /// Red(String),
356+ /// Green(String),
357+ /// Blue(String),
358+ /// }
359+ ///
360+ /// /// Combines all consecutive `Comment` nodes into a single one.
361+ /// fn combine_comments(nodes: Vec<Node>) -> Vec<Node> {
362+ /// let mut result = Vec::with_capacity(nodes.len());
363+ /// let mut iter = nodes.into_iter().peekable();
364+ /// let mut comment_text = None::<String>;
365+ /// loop {
366+ /// // Typically the closure in .next_if_map() matches on the input,
367+ /// // extracts the desired pattern into an `Ok`,
368+ /// // and puts the rest into an `Err`.
369+ /// while let Some(text) = iter.next_if_map(|node| match node {
370+ /// Node::Comment(text) => Ok(text),
371+ /// other => Err(other),
372+ /// }) {
373+ /// comment_text.get_or_insert_default().push_str(&text);
374+ /// }
375+ ///
376+ /// if let Some(text) = comment_text.take() {
377+ /// result.push(Node::Comment(text));
378+ /// }
379+ /// if let Some(node) = iter.next() {
380+ /// result.push(node);
381+ /// } else {
382+ /// break;
383+ /// }
384+ /// }
385+ /// result
386+ /// }
387+ ///# assert_eq!( // hiding the test to avoid cluttering the documentation.
388+ ///# combine_comments(vec![
389+ ///# Node::Comment("The".to_owned()),
390+ ///# Node::Comment("Quick".to_owned()),
391+ ///# Node::Comment("Brown".to_owned()),
392+ ///# Node::Red("Fox".to_owned()),
393+ ///# Node::Green("Jumped".to_owned()),
394+ ///# Node::Comment("Over".to_owned()),
395+ ///# Node::Blue("The".to_owned()),
396+ ///# Node::Comment("Lazy".to_owned()),
397+ ///# Node::Comment("Dog".to_owned()),
398+ ///# ]),
399+ ///# vec![
400+ ///# Node::Comment("TheQuickBrown".to_owned()),
401+ ///# Node::Red("Fox".to_owned()),
402+ ///# Node::Green("Jumped".to_owned()),
403+ ///# Node::Comment("Over".to_owned()),
404+ ///# Node::Blue("The".to_owned()),
405+ ///# Node::Comment("LazyDog".to_owned()),
406+ ///# ],
407+ ///# )
408+ /// ```
409+ #[ unstable( feature = "peekable_next_if_map" , issue = "143702" ) ]
410+ pub fn next_if_map < R > ( & mut self , f : impl FnOnce ( I :: Item ) -> Result < R , I :: Item > ) -> Option < R > {
411+ let unpeek = if let Some ( item) = self . next ( ) {
412+ match f ( item) {
413+ Ok ( result) => return Some ( result) ,
414+ Err ( item) => Some ( item) ,
415+ }
416+ } else {
417+ None
418+ } ;
419+ self . peeked = Some ( unpeek) ;
420+ None
421+ }
320422}
321423
322424#[ unstable( feature = "trusted_len" , issue = "37572" ) ]
0 commit comments