//! Provides the `peeking_take_while` iterator adaptor method. //! //! The `peeking_take_while` method is very similar to `take_while`, but behaves //! differently when used with a borrowed iterator (perhaps returned by //! `Iterator::by_ref`). //! //! `peeking_take_while` peeks at the next item in the iterator and runs the //! predicate on that peeked item. This avoids consuming the first item yielded //! by the underlying iterator for which the predicate returns `false`. On the //! other hand, `take_while` will consume that first item for which the //! predicate returns `false`, and it will be lost. //! //! In case the closure may have side effects, it could be necessary to apply //! [`fuse`](Iterator::fuse) on the returned iterator, to prevent the predicate //! from being called after it first returned `false`. //! //! ``` //! // Bring the `peeking_take_while` method for peekable iterators into //! // scope. //! use peeking_take_while::PeekableExt; //! //! # fn main() { //! // Let's say we have two collections we want to iterate through: `xs` and //! // `ys`. We want to perform one operation on all the leading contiguous //! // elements that match some predicate, and a different thing with the rest of //! // the elements. With the `xs`, we will use the normal `take_while`. With the //! // `ys`, we will use `peeking_take_while`. //! //! let xs: Vec = (0..100).collect(); //! let ys = xs.clone(); //! //! let mut iter_xs = xs.into_iter(); //! let mut iter_ys = ys.into_iter().peekable(); //! //! { //! // Let's do one thing with all the items that are less than 10. //! # fn do_things_with(_: T) {} //! //! let xs_less_than_ten = iter_xs.by_ref().take_while(|x| *x < 10); //! for x in xs_less_than_ten { //! do_things_with(x); //! } //! //! let ys_less_than_ten = iter_ys.by_ref().peeking_take_while(|y| *y < 10); //! for y in ys_less_than_ten { //! do_things_with(y); //! } //! } //! //! // And now we will do some other thing with the items that are greater than //! // or equal to 10. //! //! // ...except, when using plain old `take_while` we lost 10! //! assert_eq!(iter_xs.next(), Some(11)); //! //! // However, when using `peeking_take_while` we did not! Great! //! assert_eq!(iter_ys.next(), Some(10)); //! # } //! ``` #![no_std] #![forbid( clippy::as_conversions, clippy::cast_ptr_alignment, missing_docs, trivial_casts, unsafe_code )] // ANDROID: Unconditionally use std to allow building as a dylib #[macro_use] extern crate std; use core::fmt; /// The `Iterator` extension trait that provides the `peeking_take_while` /// method. /// /// See the [module documentation](./index.html) for details. pub trait PeekableExt: Iterator where I: Iterator, { /// The `peeking_take_while` method is very similar to `take_while`, but behaves /// differently when used with a borrowed iterator (perhaps returned by /// `Iterator::by_ref`). /// /// `peeking_take_while` peeks at the next item in the iterator and runs the /// predicate on that peeked item. This avoids consuming the first item yielded /// by the underlying iterator for which the predicate returns `false`. On the /// other hand, `take_while` will consume that first item for which the /// predicate returns `false`, and it will be lost. /// /// In contrast to `take_while`, iterating the iterator might call the predicate again /// after it first returned `false` (the returned iterator isn't fused). /// If that is not intended, calling [`fuse`](Iterator::fuse) on the returned iterator /// prevents that. fn peeking_take_while

(&mut self, predicate: P) -> PeekingTakeWhile<'_, I, P> where P: FnMut(&Self::Item) -> bool; } impl PeekableExt for core::iter::Peekable { #[inline] fn peeking_take_while

(&mut self, predicate: P) -> PeekingTakeWhile<'_, I, P> where P: FnMut(&Self::Item) -> bool, { PeekingTakeWhile { iter: self, predicate, } } } /// The iterator returned by `peeking_take_while`. /// /// See the [module documentation](./index.html) for details. pub struct PeekingTakeWhile<'a, I, P> where I: Iterator, { pub(crate) iter: &'a mut core::iter::Peekable, pub(crate) predicate: P, } impl fmt::Debug for PeekingTakeWhile<'_, I, P> where I: Iterator + fmt::Debug, I::Item: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PeekingTakeWhile") .field("iter", &self.iter) .finish() } } impl Iterator for PeekingTakeWhile<'_, I, P> where I: Iterator, P: FnMut(&I::Item) -> bool, { type Item = I::Item; #[inline] fn next(&mut self) -> Option { self.iter.next_if(&mut self.predicate) } #[inline] fn size_hint(&self) -> (usize, Option) { // can't know a lower bound, due to the predicate (0, self.iter.size_hint().1) } #[inline] fn fold(mut self, mut accum: B, mut f: F) -> B where F: FnMut(B, I::Item) -> B, { while let Some(x) = self.iter.next_if(&mut self.predicate) { accum = f(accum, x); } accum } } // interestingly, `PeekingTakeWhile` is not automatically fused, // even when the inner iterator is fused, see also: `tests::not_fused`. #[cfg(test)] mod tests { use crate::PeekableExt; #[test] fn basic() { let mut it0 = (1..11).peekable(); let a: u32 = it0.peeking_take_while(|&i| i < 5).sum(); let b: u32 = it0.sum(); assert_eq!(a, 10); assert_eq!(b, 45); } #[test] fn basic_fused() { let mut it0 = (1..11).peekable(); let a: u32 = it0.peeking_take_while(|&i| i < 5).fuse().sum(); let b: u32 = it0.sum(); assert_eq!(a, 10); assert_eq!(b, 45); } #[test] fn not_fused() { let mut it0 = (0..10).peekable(); let mut ax = true; let mut it1 = it0.peeking_take_while(|_| { ax = !ax; ax }); assert!(it1.next().is_none()); assert_eq!(it1.next(), Some(0)); assert!(it1.next().is_none()); assert_eq!(it1.next(), Some(1)); assert_eq!(ax, true); } #[test] fn fused() { let mut it0 = (0..10).peekable(); let mut ax = true; let mut it1 = it0 .peeking_take_while(|_| { ax = !ax; ax }) .fuse(); assert!(it1.next().is_none()); assert!(it1.next().is_none()); assert_eq!(ax, false); } }