//! An iterator adapter for arbitrary lookahead functionality. //! //! This module provides [`Lookahead`], an adapter for any iterator that allows //! you to peek ahead by any number of elements, without consuming them. //! //! ## Example //! ``` //! use rune::LookaheadExt; //! //! let mut it = vec![10, 20, 30].into_iter().lookahead(); //! //! assert_eq!(it.peek(0), Some(&10)); //! assert_eq!(it.peek(1), Some(&20)); //! assert_eq!(it.next(), Some(10)); //! assert_eq!(it.peek(0), Some(&20)); //! ``` use std::collections::VecDeque; use std::fmt; use std::iter::{Fuse, FusedIterator}; /// An iterator adapter that allows arbitrary lookahead peeking. /// /// This struct wraps an iterator and buffers items so that any future /// item can be accessed by index without consuming them. Similar to /// [`std::iter::Peekable`], but supports peeking any number of steps ahead. pub struct Lookahead where I: Iterator { iter: Fuse, buffer: VecDeque } impl Lookahead where I: Iterator { /// Creates a new [`Lookahead`] from the given iterator. /// /// This constructor is typically used indirectly via the /// [`LookaheadExt::lookahead()`] method or [`lookahead()`] free function. #[must_use] pub fn new(iter: I) -> Self { Lookahead { iter: iter.fuse(), buffer: VecDeque::new() } } /// Returns a reference to the `n`th upcoming item, if it exists. /// /// `peek(0)` is the same as peeking at the next item. /// /// This does **not consume** any items from the iterator. /// /// # Examples /// ``` /// use rune::LookaheadExt; /// /// let mut it = vec![1, 2, 3].into_iter().lookahead(); /// /// assert_eq!(it.peek(1), Some(&2)); /// assert_eq!(it.next(), Some(1)); /// ``` pub fn peek(&mut self, n: usize) -> Option<&I::Item> { while self.buffer.len() <= n { if let Some(item) = self.iter.next() { self.buffer.push_back(item); } else { break; } } self.buffer.get(n) } /// Returns a mutable reference to the `n`th upcoming item, if it exists. /// /// This allows in-place modification of peeked items before consumption. /// /// # Examples /// ``` /// use rune::LookaheadExt; /// /// let mut it = vec![1, 2, 3].into_iter().lookahead(); /// if let Some(x) = it.peek_mut(1) /// { /// *x *= 10; /// } /// assert_eq!(it.next(), Some(1)); /// assert_eq!(it.next(), Some(20)); /// ``` pub fn peek_mut(&mut self, n: usize) -> Option<&mut I::Item> { while self.buffer.len() <= n { if let Some(item) = self.iter.next() { self.buffer.push_back(item); } else { break; } } self.buffer.get_mut(n) } } impl Iterator for Lookahead where I: Iterator { type Item = I::Item; /// Retrieves the next item, consuming it. /// /// If any items were previously peeked and buffered, they are returned /// first before accessing the underlying iterator. fn next(&mut self) -> Option { if let Some(front) = self.buffer.pop_front() { Some(front) } else { self.iter.next() } } /// Provides a size hint accounting for both buffered and remaining elements. fn size_hint(&self) -> (usize, Option) { let (low, high) = self.iter.size_hint(); let buffered = self.buffer.len(); (low.saturating_add(buffered), high.and_then(|h| h.checked_add(buffered))) } } impl Clone for Lookahead where I: Iterator + Clone, I::Item: Clone { fn clone(&self) -> Self { Lookahead { iter: self.iter.clone(), buffer: self.buffer.clone() } } } impl fmt::Debug for Lookahead where I: Iterator + fmt::Debug, I::Item: fmt::Debug { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Lookahead") .field("iter", &self.iter) .field("buffer", &self.buffer) .finish() } } impl FusedIterator for Lookahead where I: Iterator + FusedIterator {} /// Extension trait to provide `.lookahead()` on all iterators. /// /// This lets you easily call `.lookahead()` on any iterator to /// create a [`Lookahead`] instance. pub trait LookaheadExt: Iterator + Sized { /// Wraps the iterator in a [`Lookahead`] adapter. fn lookahead(self) -> Lookahead; } impl LookaheadExt for I { fn lookahead(self) -> Lookahead { Lookahead::new(self) } } /// Creates a [`Lookahead`] from any iterable. /// /// This is a convenience function for use in functional-style code or /// when not using the extension trait. /// /// # Example /// ``` /// use rune::lookahead; /// /// let mut it = lookahead(vec![1, 2, 3]); /// /// assert_eq!(it.peek(2), Some(&3)); /// ``` pub fn lookahead(iterable: I) -> Lookahead where I: IntoIterator { Lookahead::new(iterable.into_iter()) }