]>
Commit | Line | Data |
---|---|---|
c295e0f8 XL |
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 | ||
a2a8927a XL |
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 | ||
c295e0f8 XL |
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> } |