1use std::iter::Fuse;
2use alloc::collections::VecDeque;
3use crate::size_hint;
4use crate::PeekingNext;
5#[cfg(doc)]
6use crate::Itertools;
7
8/// See [`multipeek()`] for more information.
9#[derive(Clone, Debug)]
10pub struct MultiPeek<I>
11 where I: Iterator
12{
13 iter: Fuse<I>,
14 buf: VecDeque<I::Item>,
15 index: usize,
16}
17
18/// An iterator adaptor that allows the user to peek at multiple `.next()`
19/// values without advancing the base iterator.
20///
21/// [`IntoIterator`] enabled version of [`Itertools::multipeek`].
22pub fn multipeek<I>(iterable: I) -> MultiPeek<I::IntoIter>
23 where I: IntoIterator
24{
25 MultiPeek {
26 iter: iterable.into_iter().fuse(),
27 buf: VecDeque::new(),
28 index: 0,
29 }
30}
31
32impl<I> MultiPeek<I>
33 where I: Iterator
34{
35 /// Reset the peeking “cursor”
36 pub fn reset_peek(&mut self) {
37 self.index = 0;
38 }
39}
40
41impl<I: Iterator> MultiPeek<I> {
42 /// Works exactly like `.next()` with the only difference that it doesn't
43 /// advance itself. `.peek()` can be called multiple times, to peek
44 /// further ahead.
45 /// When `.next()` is called, reset the peeking “cursor”.
46 pub fn peek(&mut self) -> Option<&I::Item> {
47 let ret = if self.index < self.buf.len() {
48 Some(&self.buf[self.index])
49 } else {
50 match self.iter.next() {
51 Some(x) => {
52 self.buf.push_back(x);
53 Some(&self.buf[self.index])
54 }
55 None => return None,
56 }
57 };
58
59 self.index += 1;
60 ret
61 }
62}
63
64impl<I> PeekingNext for MultiPeek<I>
65 where I: Iterator,
66{
67 fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
68 where F: FnOnce(&Self::Item) -> bool
69 {
70 if self.buf.is_empty() {
71 if let Some(r) = self.peek() {
72 if !accept(r) { return None }
73 }
74 } else if let Some(r) = self.buf.get(0) {
75 if !accept(r) { return None }
76 }
77 self.next()
78 }
79}
80
81impl<I> Iterator for MultiPeek<I>
82 where I: Iterator
83{
84 type Item = I::Item;
85
86 fn next(&mut self) -> Option<Self::Item> {
87 self.index = 0;
88 self.buf.pop_front().or_else(|| self.iter.next())
89 }
90
91 fn size_hint(&self) -> (usize, Option<usize>) {
92 size_hint::add_scalar(self.iter.size_hint(), self.buf.len())
93 }
94}
95
96// Same size
97impl<I> ExactSizeIterator for MultiPeek<I>
98 where I: ExactSizeIterator
99{}
100
101
102