1 //! Provides the `peeking_take_while` iterator adaptor method. 2 //! 3 //! The `peeking_take_while` method is very similar to `take_while`, but behaves 4 //! differently when used with a borrowed iterator (perhaps returned by 5 //! `Iterator::by_ref`). 6 //! 7 //! `peeking_take_while` peeks at the next item in the iterator and runs the 8 //! predicate on that peeked item. This avoids consuming the first item yielded 9 //! by the underlying iterator for which the predicate returns `false`. On the 10 //! other hand, `take_while` will consume that first item for which the 11 //! predicate returns `false`, and it will be lost. 12 //! 13 //! In case the closure may have side effects, it could be necessary to apply 14 //! [`fuse`](Iterator::fuse) on the returned iterator, to prevent the predicate 15 //! from being called after it first returned `false`. 16 //! 17 //! ``` 18 //! // Bring the `peeking_take_while` method for peekable iterators into 19 //! // scope. 20 //! use peeking_take_while::PeekableExt; 21 //! 22 //! # fn main() { 23 //! // Let's say we have two collections we want to iterate through: `xs` and 24 //! // `ys`. We want to perform one operation on all the leading contiguous 25 //! // elements that match some predicate, and a different thing with the rest of 26 //! // the elements. With the `xs`, we will use the normal `take_while`. With the 27 //! // `ys`, we will use `peeking_take_while`. 28 //! 29 //! let xs: Vec<u8> = (0..100).collect(); 30 //! let ys = xs.clone(); 31 //! 32 //! let mut iter_xs = xs.into_iter(); 33 //! let mut iter_ys = ys.into_iter().peekable(); 34 //! 35 //! { 36 //! // Let's do one thing with all the items that are less than 10. 37 //! # fn do_things_with<T>(_: T) {} 38 //! 39 //! let xs_less_than_ten = iter_xs.by_ref().take_while(|x| *x < 10); 40 //! for x in xs_less_than_ten { 41 //! do_things_with(x); 42 //! } 43 //! 44 //! let ys_less_than_ten = iter_ys.by_ref().peeking_take_while(|y| *y < 10); 45 //! for y in ys_less_than_ten { 46 //! do_things_with(y); 47 //! } 48 //! } 49 //! 50 //! // And now we will do some other thing with the items that are greater than 51 //! // or equal to 10. 52 //! 53 //! // ...except, when using plain old `take_while` we lost 10! 54 //! assert_eq!(iter_xs.next(), Some(11)); 55 //! 56 //! // However, when using `peeking_take_while` we did not! Great! 57 //! assert_eq!(iter_ys.next(), Some(10)); 58 //! # } 59 //! ``` 60 61 #![no_std] 62 #![forbid( 63 clippy::as_conversions, 64 clippy::cast_ptr_alignment, 65 missing_docs, 66 trivial_casts, 67 unsafe_code 68 )] 69 70 // ANDROID: Unconditionally use std to allow building as a dylib 71 #[macro_use] 72 extern crate std; 73 74 use core::fmt; 75 76 /// The `Iterator` extension trait that provides the `peeking_take_while` 77 /// method. 78 /// 79 /// See the [module documentation](./index.html) for details. 80 pub trait PeekableExt<I>: Iterator 81 where 82 I: Iterator, 83 { 84 /// The `peeking_take_while` method is very similar to `take_while`, but behaves 85 /// differently when used with a borrowed iterator (perhaps returned by 86 /// `Iterator::by_ref`). 87 /// 88 /// `peeking_take_while` peeks at the next item in the iterator and runs the 89 /// predicate on that peeked item. This avoids consuming the first item yielded 90 /// by the underlying iterator for which the predicate returns `false`. On the 91 /// other hand, `take_while` will consume that first item for which the 92 /// predicate returns `false`, and it will be lost. 93 /// 94 /// In contrast to `take_while`, iterating the iterator might call the predicate again 95 /// after it first returned `false` (the returned iterator isn't fused). 96 /// If that is not intended, calling [`fuse`](Iterator::fuse) on the returned iterator 97 /// prevents that. peeking_take_while<P>(&mut self, predicate: P) -> PeekingTakeWhile<'_, I, P> where P: FnMut(&Self::Item) -> bool98 fn peeking_take_while<P>(&mut self, predicate: P) -> PeekingTakeWhile<'_, I, P> 99 where 100 P: FnMut(&Self::Item) -> bool; 101 } 102 103 impl<I: Iterator> PeekableExt<I> for core::iter::Peekable<I> { 104 #[inline] peeking_take_while<P>(&mut self, predicate: P) -> PeekingTakeWhile<'_, I, P> where P: FnMut(&Self::Item) -> bool,105 fn peeking_take_while<P>(&mut self, predicate: P) -> PeekingTakeWhile<'_, I, P> 106 where 107 P: FnMut(&Self::Item) -> bool, 108 { 109 PeekingTakeWhile { 110 iter: self, 111 predicate, 112 } 113 } 114 } 115 116 /// The iterator returned by `peeking_take_while`. 117 /// 118 /// See the [module documentation](./index.html) for details. 119 pub struct PeekingTakeWhile<'a, I, P> 120 where 121 I: Iterator, 122 { 123 pub(crate) iter: &'a mut core::iter::Peekable<I>, 124 pub(crate) predicate: P, 125 } 126 127 impl<I, P> fmt::Debug for PeekingTakeWhile<'_, I, P> 128 where 129 I: Iterator + fmt::Debug, 130 I::Item: fmt::Debug, 131 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 133 f.debug_struct("PeekingTakeWhile") 134 .field("iter", &self.iter) 135 .finish() 136 } 137 } 138 139 impl<I, P> Iterator for PeekingTakeWhile<'_, I, P> 140 where 141 I: Iterator, 142 P: FnMut(&I::Item) -> bool, 143 { 144 type Item = I::Item; 145 146 #[inline] next(&mut self) -> Option<Self::Item>147 fn next(&mut self) -> Option<Self::Item> { 148 self.iter.next_if(&mut self.predicate) 149 } 150 151 #[inline] size_hint(&self) -> (usize, Option<usize>)152 fn size_hint(&self) -> (usize, Option<usize>) { 153 // can't know a lower bound, due to the predicate 154 (0, self.iter.size_hint().1) 155 } 156 157 #[inline] fold<B, F>(mut self, mut accum: B, mut f: F) -> B where F: FnMut(B, I::Item) -> B,158 fn fold<B, F>(mut self, mut accum: B, mut f: F) -> B 159 where 160 F: FnMut(B, I::Item) -> B, 161 { 162 while let Some(x) = self.iter.next_if(&mut self.predicate) { 163 accum = f(accum, x); 164 } 165 accum 166 } 167 } 168 169 // interestingly, `PeekingTakeWhile` is not automatically fused, 170 // even when the inner iterator is fused, see also: `tests::not_fused`. 171 172 #[cfg(test)] 173 mod tests { 174 use crate::PeekableExt; 175 176 #[test] basic()177 fn basic() { 178 let mut it0 = (1..11).peekable(); 179 let a: u32 = it0.peeking_take_while(|&i| i < 5).sum(); 180 let b: u32 = it0.sum(); 181 assert_eq!(a, 10); 182 assert_eq!(b, 45); 183 } 184 185 #[test] basic_fused()186 fn basic_fused() { 187 let mut it0 = (1..11).peekable(); 188 let a: u32 = it0.peeking_take_while(|&i| i < 5).fuse().sum(); 189 let b: u32 = it0.sum(); 190 assert_eq!(a, 10); 191 assert_eq!(b, 45); 192 } 193 194 #[test] not_fused()195 fn not_fused() { 196 let mut it0 = (0..10).peekable(); 197 let mut ax = true; 198 let mut it1 = it0.peeking_take_while(|_| { 199 ax = !ax; 200 ax 201 }); 202 assert!(it1.next().is_none()); 203 assert_eq!(it1.next(), Some(0)); 204 assert!(it1.next().is_none()); 205 assert_eq!(it1.next(), Some(1)); 206 assert_eq!(ax, true); 207 } 208 209 #[test] fused()210 fn fused() { 211 let mut it0 = (0..10).peekable(); 212 let mut ax = true; 213 let mut it1 = it0 214 .peeking_take_while(|_| { 215 ax = !ax; 216 ax 217 }) 218 .fuse(); 219 assert!(it1.next().is_none()); 220 assert!(it1.next().is_none()); 221 assert_eq!(ax, false); 222 } 223 } 224