use crate::PutBack; #[cfg(feature = "use_alloc")] use crate::PutBackN; use std::iter::Peekable; /// An iterator that allows peeking at an element before deciding to accept it. /// /// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while) /// for more information. /// /// This is implemented by peeking adaptors like peekable and put back, /// but also by a few iterators that can be peeked natively, like the slice’s /// by reference iterator (`std::slice::Iter`). pub trait PeekingNext: Iterator { /// Pass a reference to the next iterator element to the closure `accept`; /// if `accept` returns true, return it as the next element, /// else None. fn peeking_next(&mut self, accept: F) -> Option where Self: Sized, F: FnOnce(&Self::Item) -> bool; } impl<'a, I> PeekingNext for &'a mut I where I: PeekingNext, { fn peeking_next(&mut self, accept: F) -> Option where F: FnOnce(&Self::Item) -> bool, { (*self).peeking_next(accept) } } impl PeekingNext for Peekable where I: Iterator, { fn peeking_next(&mut self, accept: F) -> Option where F: FnOnce(&Self::Item) -> bool, { if let Some(r) = self.peek() { if !accept(r) { return None; } } self.next() } } impl PeekingNext for PutBack where I: Iterator, { fn peeking_next(&mut self, accept: F) -> Option where F: FnOnce(&Self::Item) -> bool, { if let Some(r) = self.next() { if !accept(&r) { self.put_back(r); return None; } Some(r) } else { None } } } #[cfg(feature = "use_alloc")] impl PeekingNext for PutBackN where I: Iterator, { fn peeking_next(&mut self, accept: F) -> Option where F: FnOnce(&Self::Item) -> bool, { if let Some(r) = self.next() { if !accept(&r) { self.put_back(r); return None; } Some(r) } else { None } } } /// An iterator adaptor that takes items while a closure returns `true`. /// /// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while) /// for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct PeekingTakeWhile<'a, I: 'a, F> where I: Iterator, { iter: &'a mut I, f: F, } impl<'a, I: 'a, F> std::fmt::Debug for PeekingTakeWhile<'a, I, F> where I: Iterator + std::fmt::Debug, { debug_fmt_fields!(PeekingTakeWhile, iter); } /// Create a `PeekingTakeWhile` pub fn peeking_take_while(iter: &mut I, f: F) -> PeekingTakeWhile where I: Iterator, { PeekingTakeWhile { iter, f } } impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F> where I: PeekingNext, F: FnMut(&I::Item) -> bool, { type Item = I::Item; fn next(&mut self) -> Option { self.iter.peeking_next(&mut self.f) } fn size_hint(&self) -> (usize, Option) { (0, self.iter.size_hint().1) } } impl<'a, I, F> PeekingNext for PeekingTakeWhile<'a, I, F> where I: PeekingNext, F: FnMut(&I::Item) -> bool, { fn peeking_next(&mut self, g: G) -> Option where G: FnOnce(&Self::Item) -> bool, { let f = &mut self.f; self.iter.peeking_next(|r| f(r) && g(r)) } } // Some iterators are so lightweight we can simply clone them to save their // state and use that for peeking. macro_rules! peeking_next_by_clone { ([$($typarm:tt)*] $type_:ty) => { impl<$($typarm)*> PeekingNext for $type_ { fn peeking_next(&mut self, accept: F) -> Option where F: FnOnce(&Self::Item) -> bool { let saved_state = self.clone(); if let Some(r) = self.next() { if !accept(&r) { *self = saved_state; } else { return Some(r) } } None } } } } peeking_next_by_clone! { ['a, T] ::std::slice::Iter<'a, T> } peeking_next_by_clone! { ['a] ::std::str::Chars<'a> } peeking_next_by_clone! { ['a] ::std::str::CharIndices<'a> } peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> } peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> } peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> } peeking_next_by_clone! { [T] ::std::iter::Empty } #[cfg(feature = "use_alloc")] peeking_next_by_clone! { ['a, T] alloc::collections::linked_list::Iter<'a, T> } #[cfg(feature = "use_alloc")] peeking_next_by_clone! { ['a, T] alloc::collections::vec_deque::Iter<'a, T> } // cloning a Rev has no extra overhead; peekable and put backs are never DEI. peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator] ::std::iter::Rev }