1 | use std::iter::Peekable; |
2 | use crate::PutBack; |
3 | #[cfg (feature = "use_alloc" )] |
4 | use crate::PutBackN; |
5 | |
6 | /// An iterator that allows peeking at an element before deciding to accept it. |
7 | /// |
8 | /// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while) |
9 | /// for more information. |
10 | /// |
11 | /// This is implemented by peeking adaptors like peekable and put back, |
12 | /// but also by a few iterators that can be peeked natively, like the slice’s |
13 | /// by reference iterator (`std::slice::Iter`). |
14 | pub trait PeekingNext : Iterator { |
15 | /// Pass a reference to the next iterator element to the closure `accept`; |
16 | /// if `accept` returns true, return it as the next element, |
17 | /// else None. |
18 | fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item> |
19 | where F: FnOnce(&Self::Item) -> bool; |
20 | } |
21 | |
22 | impl<I> PeekingNext for Peekable<I> |
23 | where I: Iterator, |
24 | { |
25 | fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item> |
26 | where F: FnOnce(&Self::Item) -> bool |
27 | { |
28 | if let Some(r) = self.peek() { |
29 | if !accept(r) { |
30 | return None; |
31 | } |
32 | } |
33 | self.next() |
34 | } |
35 | } |
36 | |
37 | impl<I> PeekingNext for PutBack<I> |
38 | where I: Iterator, |
39 | { |
40 | fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item> |
41 | where F: FnOnce(&Self::Item) -> bool |
42 | { |
43 | if let Some(r) = self.next() { |
44 | if !accept(&r) { |
45 | self.put_back(r); |
46 | return None; |
47 | } |
48 | Some(r) |
49 | } else { |
50 | None |
51 | } |
52 | } |
53 | } |
54 | |
55 | #[cfg (feature = "use_alloc" )] |
56 | impl<I> PeekingNext for PutBackN<I> |
57 | where I: Iterator, |
58 | { |
59 | fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item> |
60 | where F: FnOnce(&Self::Item) -> bool |
61 | { |
62 | if let Some(r) = self.next() { |
63 | if !accept(&r) { |
64 | self.put_back(r); |
65 | return None; |
66 | } |
67 | Some(r) |
68 | } else { |
69 | None |
70 | } |
71 | } |
72 | } |
73 | |
74 | /// An iterator adaptor that takes items while a closure returns `true`. |
75 | /// |
76 | /// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while) |
77 | /// for more information. |
78 | #[must_use = "iterator adaptors are lazy and do nothing unless consumed" ] |
79 | pub struct PeekingTakeWhile<'a, I: 'a, F> |
80 | where I: Iterator, |
81 | { |
82 | iter: &'a mut I, |
83 | f: F, |
84 | } |
85 | |
86 | impl<'a, I: 'a, F> std::fmt::Debug for PeekingTakeWhile<'a, I, F> |
87 | where |
88 | I: Iterator + std::fmt::Debug, |
89 | { |
90 | debug_fmt_fields!(PeekingTakeWhile, iter); |
91 | } |
92 | |
93 | /// Create a `PeekingTakeWhile` |
94 | pub fn peeking_take_while<I, F>(iter: &mut I, f: F) -> PeekingTakeWhile<I, F> |
95 | where I: Iterator, |
96 | { |
97 | PeekingTakeWhile { |
98 | iter, |
99 | f, |
100 | } |
101 | } |
102 | |
103 | impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F> |
104 | where I: PeekingNext, |
105 | F: FnMut(&I::Item) -> bool, |
106 | |
107 | { |
108 | type Item = I::Item; |
109 | fn next(&mut self) -> Option<Self::Item> { |
110 | self.iter.peeking_next(&mut self.f) |
111 | } |
112 | |
113 | fn size_hint(&self) -> (usize, Option<usize>) { |
114 | (0, self.iter.size_hint().1) |
115 | } |
116 | } |
117 | |
118 | // Some iterators are so lightweight we can simply clone them to save their |
119 | // state and use that for peeking. |
120 | macro_rules! peeking_next_by_clone { |
121 | ([$($typarm:tt)*] $type_:ty) => { |
122 | impl<$($typarm)*> PeekingNext for $type_ { |
123 | fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item> |
124 | where F: FnOnce(&Self::Item) -> bool |
125 | { |
126 | let saved_state = self.clone(); |
127 | if let Some(r) = self.next() { |
128 | if !accept(&r) { |
129 | *self = saved_state; |
130 | } else { |
131 | return Some(r) |
132 | } |
133 | } |
134 | None |
135 | } |
136 | } |
137 | } |
138 | } |
139 | |
140 | peeking_next_by_clone! { ['a, T] ::std::slice::Iter<'a, T> } |
141 | peeking_next_by_clone! { ['a] ::std::str::Chars<'a> } |
142 | peeking_next_by_clone! { ['a] ::std::str::CharIndices<'a> } |
143 | peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> } |
144 | peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> } |
145 | peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> } |
146 | peeking_next_by_clone! { [T] ::std::iter::Empty<T> } |
147 | #[cfg (feature = "use_alloc" )] |
148 | peeking_next_by_clone! { ['a, T] alloc::collections::linked_list::Iter<'a, T> } |
149 | #[cfg (feature = "use_alloc" )] |
150 | peeking_next_by_clone! { ['a, T] alloc::collections::vec_deque::Iter<'a, T> } |
151 | |
152 | // cloning a Rev has no extra overhead; peekable and put backs are never DEI. |
153 | peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator] |
154 | ::std::iter::Rev<I> } |
155 | |