1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
use std::collections::VecDeque; use std::vec::IntoIter; /// A [`TakeWhile`]-like struct that tests a predicate by peeking rather than consuming an iterator. /// /// rustlib's [`TakeWhile`] consumes items in an iterator until its predicate is no longer satisfied. /// This means that the first item that fails the predicate will also be consumed. For example, /// /// ```rust /// let nums = vec![1, 2, 3, 4, 5]; /// let mut iter = nums.iter(); /// let less_than_4: Vec<usize> = iter.by_ref().take_while(|n| **n < 4).cloned().collect(); /// assert_eq!(less_than_4, &[1, 2, 3]); /// assert_eq!(iter.next(), Some(&5)); // 4 was consumed! /// ``` /// /// `PeekingTakeWhile` implements a [`TakeWhile`]-like functionality without consuming items that fail /// its predicate. /// /// TODO: Ideally a `PeekingTakeWhile` would take a [`Peekable`] trait object rather than a /// `PeekIter`, but rustlib doesn't provide a [`Peekable`] trait yet. See the [Pre-RFC]. /// /// [`TakeWhile`]: core::iter::TakeWhile /// [`Peekable`]: core::iter::Peekable /// [Pre-RFC]: https://internals.rust-lang.org/t/pre-rfc-make-peekable-trait-for-iterator struct PeekingTakeWhile<'a, T, P> where T: Clone + 'a, P: Fn(&T) -> bool, { /// A mutable reference to the underlying iterator is taken because we actually do want to /// consume items that match the predicate. peeker: &'a mut PeekIter<T>, predicate: P, } impl<'a, T, P> Iterator for PeekingTakeWhile<'a, T, P> where T: Clone + 'a, P: Fn(&T) -> bool, { type Item = T; fn next(&mut self) -> Option<T> { if let Some(v) = self.peeker.peek() { if (self.predicate)(&v) { return self.peeker.next(); } } None } } /// An iterator that supports arbitrary-length peeking. /// /// This struct is a beefed-up version of rustlib's [`Peekable`], which supports only peeking at the /// next item in an iterator. Multi-length peeks may be required by applications that need to /// establish a context; for example, a parser. /// /// [`Peekable`]: core::iter::Peekable pub struct PeekIter<T> where T: Clone, { iter: IntoIter<T>, /// A store of items we had to consume from the iterator for peeking. lookahead: VecDeque<Option<T>>, } impl<T> PeekIter<T> where T: Clone, { pub fn new(iter: IntoIter<T>) -> Self { let mut lookahead = VecDeque::new(); lookahead.reserve(5); // optimistically we won't be peeking more than this Self { iter, lookahead } } /// Returns a reference to the next value in the iterator, without consuming it, or `None` if /// the iteration is complete. pub fn peek(&mut self) -> Option<&T> { if self.lookahead.is_empty() { // Hopefully the branch gets optimized out. Not sure if we can reduce it. let next = self.iter.next(); self.lookahead.push_back(next); } self.lookahead[0].as_ref() } /// Returns a deque of up to `n` peeked items mapped over a function `f`. /// /// The length of the returned deque is `n` or the number of items remaining in the iteration, /// whichever is lower. pub fn peek_map_n<R>(&mut self, n: usize, f: fn(&T) -> R) -> VecDeque<R> { while self.lookahead.len() < n { let next = self.iter.next(); self.lookahead.push_back(next); } self.lookahead .iter() .take(n) .filter_map(|o| o.as_ref()) .map(f) .collect() } /// Adds an item to the front of the current iteration. pub fn push_front(&mut self, item: T) { self.lookahead.push_front(Some(item)); } } impl<T> Iterator for PeekIter<T> where T: Clone, { type Item = T; fn next(&mut self) -> Option<Self::Item> { self.lookahead .pop_front() // Note that unwrap_or *cannot* be used here because it is easily evaluated, and will // evaluate `self.iter.next()` before the lookahead is checked! .unwrap_or_else(|| self.iter.next()) } }