rune/src/iter.rs

210 lines
5.0 KiB
Rust
Raw Normal View History

//! 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<I>
where I: Iterator
{
iter: Fuse<I>,
buffer: VecDeque<I::Item>
}
impl<I> Lookahead<I> 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<I> Iterator for Lookahead<I> 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<Self::Item>
{
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<usize>)
{
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<I> Clone for Lookahead<I>
where I: Iterator + Clone,
I::Item: Clone
{
fn clone(&self) -> Self
{
Lookahead { iter: self.iter.clone(),
buffer: self.buffer.clone() }
}
}
impl<I> fmt::Debug for Lookahead<I>
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<I> FusedIterator for Lookahead<I> 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<Self>;
}
impl<I: Iterator> LookaheadExt for I
{
fn lookahead(self) -> Lookahead<Self>
{
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<I>(iterable: I) -> Lookahead<I::IntoIter>
where I: IntoIterator
{
Lookahead::new(iterable.into_iter())
}