blob: cd0945a524ea9325d797d8339c8ae904121d0201 [file] [log] [blame]
Jakub Kotura425e552020-12-21 17:28:15 +01001use std::iter::Peekable;
2use crate::PutBack;
Joel Galenson6f798712021-04-01 17:03:06 -07003#[cfg(feature = "use_alloc")]
Jakub Kotura425e552020-12-21 17:28:15 +01004use crate::PutBackN;
5
6/// An iterator that allows peeking at an element before deciding to accept it.
7///
Joel Galensonb593e252021-06-21 13:15:57 -07008/// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while)
Jakub Kotura425e552020-12-21 17:28:15 +01009/// 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`).
14pub 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
22impl<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
37impl<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
Joel Galenson6f798712021-04-01 17:03:06 -070055#[cfg(feature = "use_alloc")]
Jakub Kotura425e552020-12-21 17:28:15 +010056impl<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///
Joel Galensonb593e252021-06-21 13:15:57 -070076/// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while)
Jakub Kotura425e552020-12-21 17:28:15 +010077/// for more information.
78#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
79pub struct PeekingTakeWhile<'a, I: 'a, F>
80 where I: Iterator,
81{
82 iter: &'a mut I,
83 f: F,
84}
85
David LeGareb72e9052022-03-02 16:21:08 +000086impl<'a, I: 'a, F> std::fmt::Debug for PeekingTakeWhile<'a, I, F>
87where
88 I: Iterator + std::fmt::Debug,
89{
90 debug_fmt_fields!(PeekingTakeWhile, iter);
91}
92
Jakub Kotura425e552020-12-21 17:28:15 +010093/// Create a PeekingTakeWhile
94pub 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
103impl<'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>) {
Joel Galenson6f798712021-04-01 17:03:06 -0700114 (0, self.iter.size_hint().1)
Jakub Kotura425e552020-12-21 17:28:15 +0100115 }
116}
117
118// Some iterators are so lightweight we can simply clone them to save their
119// state and use that for peeking.
120macro_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
140peeking_next_by_clone! { ['a, T] ::std::slice::Iter<'a, T> }
141peeking_next_by_clone! { ['a] ::std::str::Chars<'a> }
142peeking_next_by_clone! { ['a] ::std::str::CharIndices<'a> }
143peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> }
144peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> }
145peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> }
146peeking_next_by_clone! { [T] ::std::iter::Empty<T> }
Joel Galenson6f798712021-04-01 17:03:06 -0700147#[cfg(feature = "use_alloc")]
148peeking_next_by_clone! { ['a, T] alloc::collections::linked_list::Iter<'a, T> }
149#[cfg(feature = "use_alloc")]
150peeking_next_by_clone! { ['a, T] alloc::collections::vec_deque::Iter<'a, T> }
Jakub Kotura425e552020-12-21 17:28:15 +0100151
152// cloning a Rev has no extra overhead; peekable and put backs are never DEI.
153peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator]
154 ::std::iter::Rev<I> }