• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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