itertools/
multipeek_impl.rs

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