peekmore 0.5.4

Iterator which can peek forward multiple elements.
Documentation
#![no_std]
#![deny(missing_docs)]
#![deny(clippy::all)]

//! **Synopsis:**
//!
//! This crate introduces a multi-peekable iterator.
//! The iterator is similar to [`Peekable`]. The main difference is that [`Peekable`] only
//! allows you to peek at the next element and no further. This crate aims to take that limitation
//! away.
//!
//! **A peek at how it works:**
//!
//! To enable peeking at multiple elements ahead of consuming a next element, the iterator uses a
//! traversable queue which holds the elements which you can peek at, but have not been
//! consumed (yet).
//! By default the underlying data structure of this queue is a Vec. By enabling the `smallvec`
//! feature, you can opt-in to use SmallVec as the underlying queue data structure. SmallVec uses
//! the stack for a limited amount of elements and will only allocate on the heap if this maximum
//! amount of elements is reached. SmallVec support for `no_std` is experimental and currently
//! [requires] a nightly compiler.
//!
//!
//! **Illustrated example:**
//!
//! An illustrated example can be found at the [`PeekMoreIterator::peek`] documentation.
//!
//!
//! **Usage example:**
//!
//! ```rust
//! use peekmore::PeekMore;
//!
//! let iterable = [1, 2, 3, 4];
//! let mut iter = iterable.iter().peekmore();
//!
//! // Peek at the first element.
//! let v1 = iter.peek();
//! assert_eq!(v1, Some(&&1));
//!
//! // Consume the first element.
//! let v1c = iter.next();
//! assert_eq!(v1c, Some(&1));
//!
//! // Peek at the second element (the element our cursor points at also moved to the second element,
//! // since the first element was consumed.)
//! let v2 = iter.peek();
//! assert_eq!(v2, Some(&&2));
//!
//! // Advance the cursor. The cursor will now point to the third element.
//! let _ = iter.advance_cursor();
//!
//! // Check that it is indeed at the third element.
//! let v3 = iter.peek();
//! assert_eq!(v3, Some(&&3));
//!
//! // Reset the position the cursor points at. The cursor will point to the first unconsumed element
//! // again.
//! iter.reset_cursor();
//!
//! // Check that we are indeed at the second element again.
//! let v2 = iter.peek();
//! assert_eq!(v2, Some(&&2));
//!
//! // Shift the position of the cursor to the right twice by chaining the advance_view method.
//! let _ = iter.advance_cursor().advance_cursor();
//!
//! // Verify that the cursor indeed points at the fourth element.
//! let v4 = iter.peek();
//! assert_eq!(v4, Some(&&4));
//!
//! // Reset the position which the cursor points at again.
//! iter.reset_cursor();
//!
//! // We can also advance the cursor and peek with a single operation.
//! let v3 = iter.peek_next();
//! assert_eq!(v3, Some(&&3));
//! ```
//!
//!
//! [`Peekable`]: https://doc.rust-lang.org/core/iter/struct.Peekable.html
//! [`PeekMoreIterator::peek`]: struct.PeekMoreIterator.html#method.peek
//! [requires]: https://github.com/servo/rust-smallvec/issues/160

/// We need to allocate elements which haven't been consumed by the PeekMore iterator.
extern crate alloc;

/// Import std only when running doc tests without errors. Std will not be included outside of
/// doctest based binaries.
///
/// See [rust#54010](https://github.com/rust-lang/rust/issues/54010) for the error thrown by `doctest`
/// if no allocator is present (e.g. with just core/alloc).
/// Note that `cfg(doctest)` requires Rust 1.40 ([tracking issue](https://github.com/rust-lang/rust/issues/62210)).
/// As a result of the above, `doctest` is disabled on the CI for Rust versions below `1.40`.
#[cfg(doctest)]
extern crate std;

/// Use the system allocator when running doc tests.
///
/// See [rust#54010](https://github.com/rust-lang/rust/issues/54010) for the error thrown by `doctest`
/// if no allocator is present (e.g. with just core/alloc).
/// Note that `cfg(doctest)` requires Rust 1.40 ([tracking issue](https://github.com/rust-lang/rust/issues/62210)).
/// As a result of the above, `doctest` is disabled on the CI for Rust versions below `1.40`.
#[cfg(doctest)]
#[global_allocator]
static A: std::alloc::System = std::alloc::System;

use core::iter::FusedIterator;

/// We use a Vec to queue iterator elements if the smallvec feature is disabled.
#[cfg(not(feature = "smallvec"))]
use alloc::vec::Vec;

/// If the smallvec feature is enabled, we use a SmallVec to queue iterator elements instead of a Vec.
#[cfg(feature = "smallvec")]
use smallvec::SmallVec;

/// Trait which allows you to create an iterator which allows us to peek at any unconsumed element.
pub trait PeekMore: Iterator + Sized {
    /// Create an iterator where we can look (peek) forward multiple times from an existing iterator.
    fn peekmore(self) -> PeekMoreIterator<Self>;
}

impl<I: Iterator> PeekMore for I {
    fn peekmore(self) -> PeekMoreIterator<I> {
        PeekMoreIterator {
            iterator: self,

            #[cfg(not(feature = "smallvec"))]
            queue: Vec::new(),

            #[cfg(feature = "smallvec")]
            queue: SmallVec::new(),

            cursor: 0usize,
        }
    }
}

/// Default stack size for SmallVec.
/// Admittedly the current size is chosen quite arbitrarily.
#[cfg(feature = "smallvec")]
const DEFAULT_STACK_SIZE: usize = 256;

/// This iterator makes it possible to peek multiple times without consuming a value.
/// In reality the underlying iterator will be consumed, but the values will be stored in a local
/// queue. This queue allows us to move around unconsumed elements (as far as the iterator is concerned).
#[derive(Clone, Debug)]
pub struct PeekMoreIterator<I: Iterator> {
    /// Inner iterator. Consumption of this inner iterator does not represent consumption of the
    /// PeekMoreIterator.
    iterator: I,

    /// The queue represent the items of our iterator which have not been consumed, but have been
    /// prepared to view ('peek' at) without consuming them. Once an element has been consumed by
    /// the iterator, it is no longer possible to peek at it either (and will be removed from the
    /// queue).
    #[cfg(not(feature = "smallvec"))]
    queue: Vec<Option<I::Item>>,
    #[cfg(feature = "smallvec")]
    queue: SmallVec<[Option<I::Item>; DEFAULT_STACK_SIZE]>,

    /// The cursor helps us determine which item we currently have in view.
    ///
    /// If the cursor is 0, we have not advanced (or have reset) our peeking window, and
    /// it will point to the equivalent element as what [`core::iter::Peekable::peek`] would point to.  
    ///
    /// [`core::iter::Peekable::peek`]: https://doc.rust-lang.org/core/iter/struct.Peekable.html#method.peek
    cursor: usize,
}

impl<I: Iterator> PeekMoreIterator<I> {
    /// Get a reference to the element where the cursor currently points at (if such element exists).
    /// Sometimes we also call this the current 'view'.
    ///
    /// If we haven't advanced our cursor, that will be the same element as the one `next()` would
    /// return, but if we have moved our cursor, it will be the element we moved to instead.
    /// Note that the cursor can't ever point at an element (which existed) before the first
    /// unconsumed element within the iterator. In a sense the cursor moves independently within the
    /// iterator. But it will always stick to unconsumed elements.
    ///
    /// The following illustration aims to show how `peek()` behaves. `i` represents the position
    /// of the iterator (i.e. the next value that will be returned if `next()` is called) and `j`
    /// represents the position of the cursor (i.e. the current element referenced if
    /// `peek()` is called).
    /// In example code next to the illustrations, the first element `1` is analogous to `A`,
    /// `2` to `B` etc.
    ///
    /// * start:
    ///
    /// ```rust
    /// use peekmore::PeekMore;
    ///
    /// // Initialize our iterator.
    /// let iterable = [1, 2, 3, 4];
    /// let mut iterator = iterable.iter().peekmore();
    /// ```
    ///
    /// ```txt
    /// -----     -----      -----     -----
    /// | A | --> | B |  --> | C | --> | D | --> None --> None --> ...
    /// -----     -----      -----     -----
    ///   ^
    ///   i, j
    /// ```
    ///
    /// * call `peek()`:
    ///
    /// ```rust
    /// # use peekmore::PeekMore;
    /// # let iterable = [1, 2, 3, 4];
    /// # let mut iterator = iterable.iter().peekmore();
    /// let j = iterator.peek();
    /// assert_eq!(j, Some(&&1));
    /// ```
    ///
    /// ```txt
    /// -----     -----      -----     -----
    /// | A | --> | B |  --> | C | --> | D | --> None --> None --> ...
    /// -----     -----      -----     -----
    ///   ^
    ///   i, j
    ///      returns Some(&A)
    ///
    /// ```
    ///
    /// * call `advance_cursor()`
    ///
    /// ```rust
    /// # use peekmore::PeekMore;
    /// # let iterable = [1, 2, 3, 4];
    /// # let mut iterator = iterable.iter().peekmore();
    /// let iter = iterator.advance_cursor();
    /// ```
    ///
    /// ```txt
    /// -----     -----      -----     -----
    /// | A | --> | B |  --> | C | --> | D | --> None --> None --> ...
    /// -----     -----      -----     -----
    ///   ^         ^
    ///   i         j
    /// ```
    ///
    /// * call `peek()`
    ///   _or_ `peek(); peek()`  _or_ `peek(); peek(); peek()` etc.
    ///
    /// (The reference returned by `peek()` will not change, similar to the behaviour of
    /// [`core::iter::Peekable::peek`].
    ///      In order to move to the next peekable element, we need to advance our view.)
    ///
    /// ```rust
    /// # use peekmore::PeekMore;
    /// # let iterable = [1, 2, 3, 4];
    /// # let mut iterator = iterable.iter().peekmore();
    /// # let iter = iterator.advance_cursor();
    /// let j = iterator.peek();
    /// assert_eq!(j, Some(&&2));
    ///
    /// // Calling peek() multiple times doesn't shift the position of our cursor;
    /// // a reference to the same element will be returned each call.
    /// assert_eq!(iterator.peek(), Some(&&2));
    /// assert_eq!(iterator.peek(), Some(&&2));
    /// ```
    ///
    /// ```txt
    /// -----     -----      -----     -----
    /// | A | --> | B |  --> | C | --> | D | --> None --> None --> ...
    /// -----     -----      -----     -----
    ///   ^         ^
    ///   i         j
    ///             returns Some(&B)
    /// ```
    ///
    ///
    /// * call `next()`
    ///     (i.e. advance the iterator; the element represented by A will be consumed)
    ///
    /// ```rust
    /// # use peekmore::PeekMore;
    /// # let iterable = [1, 2, 3, 4];
    /// # let mut iterator = iterable.iter().peekmore();
    /// # let iter = iterator.advance_cursor();
    /// let i = iterator.next();
    /// assert_eq!(i, Some(&1));
    /// ```
    ///
    /// ```txt
    /// -----     -----      -----     -----
    /// | A |     | B |  --> | C | --> | D | --> None --> None --> ...
    /// -----     -----      -----     -----
    ///             ^
    ///             i, j
    ///  returns Some(A)
    /// ```
    ///
    /// * call `next()`.
    ///     (i.e. advance the iterator again; we'll see that the cursor position shifts to the
    ///      next iterator position if the iterator consumes elements where our cursor pointed at
    ///      previously (that is if `j < i`))
    ///
    ///
    /// ```rust
    /// # use peekmore::PeekMore;
    /// # let iterable = [1, 2, 3, 4];
    /// # let mut iterator = iterable.iter().peekmore();
    /// # let iter = iterator.advance_cursor();
    /// # let _ = iterator.next();
    /// // Show that the cursor still points at the second element.
    /// let j = iterator.peek();
    /// assert_eq!(j, Some(&&2));
    ///
    /// // Consume the second element.
    /// let i = iterator.next();
    /// assert_eq!(i, Some(&2));
    ///
    /// // Our cursor previously pointed at the element represented by B. Since that element has
    /// // been consumed, the cursor shifts to the next unconsumed element: C.
    /// let j = iterator.peek();
    /// assert_eq!(j, Some(&&3));
    ///
    ///
    /// ```
    ///
    /// ```txt
    /// -----     -----      -----     -----
    /// | A |     | B |      | C | --> | D | --> None --> None --> ...
    /// -----     -----      -----     -----
    ///                        ^
    ///                        i, j
    ///           returns Some(B)
    /// ```
    ///
    /// * Consume more elements by calling `next()` until we reach `None`:
    ///
    /// ```rust
    /// # use peekmore::PeekMore;
    /// # let iterable = [1, 2, 3, 4];
    /// # let mut iterator = iterable.iter().peekmore();
    /// # let iter = iterator.advance_cursor();
    /// # let _ = iterator.next();
    /// # let j = iterator.peek();
    /// # assert_eq!(j, Some(&&2));
    /// # let i = iterator.next();
    /// # assert_eq!(i, Some(&2));
    /// # let j = iterator.peek();
    /// # assert_eq!(j, Some(&&3));
    /// let i = iterator.next();
    /// assert_eq!(i, Some(&3));
    ///
    /// let j = iterator.peek();
    /// assert_eq!(j, Some(&&4));
    ///
    /// let i = iterator.next();
    /// assert_eq!(i, Some(&4));
    ///
    /// let j = iterator.peek();
    /// assert_eq!(j, None);
    ///
    /// let i = iterator.next();
    /// assert_eq!(i, None);
    /// ```
    /// [`core::iter::Peekable::peek`]: https://doc.rust-lang.org/core/iter/struct.Peekable.html#method.peek
    #[inline]
    pub fn peek(&mut self) -> Option<&I::Item> {
        self.fill_queue(self.cursor);
        self.queue.get(self.cursor).and_then(|v| v.as_ref())
    }

    // Convenient as we don't have to re-assign our mutable borrow on the 'user' side.
    /// Advance the cursor to the next element and return a reference to that value.
    #[inline]
    pub fn peek_next(&mut self) -> Option<&I::Item> {
        let this = self.advance_cursor();
        this.peek()
    }

    /// Try to peek at a previous element. If no such element exists (i.e. our cursor is already
    /// at the same point as the next iterator element), it will return an `Err` result containing a
    /// [`PeekMoreError::ElementHasBeenConsumed`].
    /// If a previous element does exist, an option wrapped in an `Ok` result will be returned.
    ///
    /// [`PeekMoreError::ElementHasBeenConsumed`]: enum.PeekMoreError.html#variant.ElementHasBeenConsumed
    #[inline]
    pub fn peek_previous(&mut self) -> Result<Option<&I::Item>, PeekMoreError> {
        if self.cursor >= 1 {
            self.move_cursor_back().map(|iter| iter.peek())
        } else {
            Err(PeekMoreError::ElementHasBeenConsumed)
        }
    }

    /// Move the cursor `n` steps forward and peek at the element the cursor then points to.
    #[inline]
    pub fn peek_forward(&mut self, n: usize) -> Option<&I::Item> {
        let this = self.advance_cursor_by(n);
        this.peek()
    }

    /// Move the cursor `n` steps backward and peek at the element the cursor then points to.
    ///
    /// If there aren't `n` elements prior to the element the cursor currently points at, a
    /// [`PeekMoreError::ElementHasBeenConsumed`] is returned instead.
    /// The cursor will then stay at the position it was prior to calling this method.
    ///
    /// If you want to peek at the first unconsumed element instead of returning with an error, you
    /// can use the [`peek_backward_or_first`] method instead of this one.
    ///
    /// [`PeekMoreError::ElementHasBeenConsumed`]: enum.PeekMoreError.html#variant.ElementHasBeenConsumed
    /// [`peek_backward_or_first`]: struct.PeekMoreIterator.html#method.peek_backward_or_first
    #[inline]
    pub fn peek_backward(&mut self, n: usize) -> Result<Option<&I::Item>, PeekMoreError> {
        let _ = self.move_cursor_back_by(n)?;

        Ok(self.peek())
    }

    /// Move the cursor `n` steps backward and peek at the element the cursor then points to, or
    /// if there aren't `n` elements prior to the element the cursor currently points to, peek at
    /// the first unconsumed element instead.
    #[inline]
    pub fn peek_backward_or_first(&mut self, n: usize) -> Option<&I::Item> {
        if self.move_cursor_back_by(n).is_err() {
            self.reset_cursor();
        }

        self.peek()
    }

    /// Peek at the nth element without moving the cursor.
    #[inline]
    pub fn peek_nth(&mut self, n: usize) -> Option<&I::Item> {
        self.fill_queue(n);
        self.queue.get(n).and_then(|v| v.as_ref())
    }

    /// Move the cursor to the next peekable element.
    /// This does not advance the iterator itself. To advance the iterator, use [`Iterator::next()`].
    ///
    /// A mutable reference to the iterator is returned.
    /// This operation can be chained.
    ///
    /// [`Iterator::next()`]: struct.PeekMoreIterator.html#impl-Iterator
    #[inline]
    pub fn advance_cursor(&mut self) -> &mut PeekMoreIterator<I> {
        self.increment_cursor();
        self
    }

    /// Move the cursor `n` elements forward.
    /// This does not advance the iterator itself. To advance the iterator, use [`Iterator::next()`].
    ///
    /// [`Iterator::next()`]: struct.PeekMoreIterator.html#impl-Iterator
    #[inline]
    pub fn advance_cursor_by(&mut self, n: usize) -> &mut PeekMoreIterator<I> {
        self.cursor += n;
        self
    }

    /// Moves the cursor forward for as many elements as a predicate is true.
    #[inline]
    pub fn advance_cursor_while<P: Fn(Option<&I::Item>) -> bool>(
        &mut self,
        predicate: P,
    ) -> &mut PeekMoreIterator<I> {
        let view = self.peek();

        if predicate(view) {
            self.increment_cursor();
            self.advance_cursor_while(predicate)
        } else {
            self.decrement_cursor();
            self
        }
    }

    /// Move the cursor to the previous peekable element.
    /// If such an element doesn't exist, returns a [`PeekMoreError::ElementHasBeenConsumed`].
    ///
    /// If we can move to a previous element, a mutable reference to the iterator,
    /// wrapped in the `Ok` variant of `Result` will be returned.
    ///
    /// [`PeekMoreError::ElementHasBeenConsumed`]: enum.PeekMoreError.html#variant.ElementHasBeenConsumed
    #[inline]
    pub fn move_cursor_back(&mut self) -> Result<&mut PeekMoreIterator<I>, PeekMoreError> {
        if self.cursor >= 1 {
            self.decrement_cursor();
            Ok(self)
        } else {
            Err(PeekMoreError::ElementHasBeenConsumed)
        }
    }

    /// Move the cursor `n` elements backward. If there aren't `n` unconsumed elements prior to the
    /// cursor it will return an error. In case of an error, the cursor will stay at the position
    /// it pointed at prior to calling this method.
    ///
    /// If you want to reset the cursor to the first unconsumed element even if there aren't `n`
    /// unconsumed elements before the position the cursor points at, you can use the
    /// [`move_backward_or_reset`] method instead.
    ///
    /// [`move_backward_or_reset`]: struct.PeekMoreIterator.html#method.move_backward_or_reset
    #[inline]
    pub fn move_cursor_back_by(
        &mut self,
        n: usize,
    ) -> Result<&mut PeekMoreIterator<I>, PeekMoreError> {
        if self.cursor < n {
            Err(PeekMoreError::ElementHasBeenConsumed)
        } else {
            self.cursor -= n;
            Ok(self)
        }
    }

    /// Move the cursor `n` elements backward or reset to the first non consumed element if
    /// we can't move the cursor `n` elements to the back.
    #[inline]
    pub fn move_cursor_back_or_reset(&mut self, n: usize) -> &mut PeekMoreIterator<I> {
        if self.cursor < n {
            self.reset_cursor();
        } else {
            self.cursor -= n;
        }

        self
    }

    /// Move the cursor to the n-th element of the queue.
    #[inline]
    pub fn move_nth(&mut self, n: usize) -> &mut PeekMoreIterator<I> {
        self.cursor = n;
        self
    }

    /// Deprecated: use [`reset_cursor`] instead.
    ///
    /// [`reset_cursor`]: struct.PeekMoreIterator.html#method.reset_cursor
    #[deprecated]
    #[inline]
    pub fn reset_view(&mut self) {
        self.reset_cursor()
    }

    /// Reset the position of the cursor. If we call [`peek`] just after a reset,
    /// it will return a reference to the first element again.
    ///
    /// [`peek`]: struct.PeekMoreIterator.html#method.peek
    #[inline]
    pub fn reset_cursor(&mut self) {
        self.cursor = 0;
    }

    /// Fills the queue up to (including) the cursor.
    #[inline]
    fn fill_queue(&mut self, required_elements: usize) {
        let stored_elements = self.queue.len();

        if stored_elements <= required_elements {
            for _ in stored_elements..=required_elements {
                self.push_next_to_queue()
            }
        }
    }

    /// Consume the underlying iterator and push an element to the queue.
    #[inline]
    fn push_next_to_queue(&mut self) {
        let item = self.iterator.next();
        self.queue.push(item);
    }

    /// Increment the cursor which points to the current peekable item.
    /// Note: if the cursor is [core::usize::MAX], it will not increment any further.
    ///
    /// [core::usize::MAX]: https://doc.rust-lang.org/core/usize/constant.MAX.html
    #[inline]
    fn increment_cursor(&mut self) {
        // do not overflow
        if self.cursor < core::usize::MAX {
            self.cursor += 1;
        }
    }

    /// Decrement the cursor which points to the current peekable item.
    /// Note: if the cursor is [core::usize::MIN], it will not decrement any further.
    ///
    /// [core::usize::MIN]: https://doc.rust-lang.org/core/usize/constant.MIN.html
    #[inline]
    fn decrement_cursor(&mut self) {
        if self.cursor > core::usize::MIN {
            self.cursor -= 1;
        }
    }

    #[doc(hidden)]
    #[cfg(test)]
    fn cursor(&self) -> usize {
        self.cursor
    }

    /// Remove all elements from the start of the iterator until reaching the same
    /// position as the cursor by calling `Iterator::next()`
    ///
    /// After calling this method, `iter.peek() == iter.next().as_ref()`
    ///```rust
    /// use peekmore::PeekMore;
    ///
    /// let iterable = [1, 2, 3, 4];
    /// let mut iter = iterable.iter().peekmore();
    ///
    /// iter.advance_cursor_by(2);
    /// assert_eq!(iter.peek(), Some(&&3));
    /// assert_eq!(iter.next(), Some(&1));
    /// iter.truncate_iterator_to_cursor();
    /// assert_eq!(iter.peek(), Some(&&3));
    /// assert_eq!(iter.next(), Some(&3));
    ///```
    pub fn truncate_iterator_to_cursor(&mut self) {
        // if the cursor and the queue length are equal,
        // then we want to clear the queue completely
        let is_equal = self.cursor == self.queue.len();

        // if the cursor is greater than the queue length,
        // we want to remove the overflow from the iterator
        for _ in 0..self.cursor.saturating_sub(self.queue.len()) {
            let _ = self.iterator.next();
        }

        self.cursor = 0;

        // if `self.queue.pop()` is `None`, then it is not necessary
        // to clear the queue
        //
        // otherwise, we pop the last item and clear the queue.
        // if the cursor and queue were equal, then we discard the value
        //
        // otherwise we insert it back into the queue
        if let Some(v) = self.queue.pop() {
            self.queue.clear();
            if !is_equal {
                self.queue.push(v);
            }
        }
    }
}

impl<'a, I: Iterator> Iterator for PeekMoreIterator<I> {
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let res = if self.queue.is_empty() {
            self.iterator.next()
        } else {
            self.queue.remove(0)
        };

        self.decrement_cursor();

        res
    }
}

/// Uses [`ExactSizeIterator`] default implementation.
///
/// [`ExactSizeIterator`]: https://doc.rust-lang.org/core/iter/trait.ExactSizeIterator.html
impl<I: ExactSizeIterator> ExactSizeIterator for PeekMoreIterator<I> {}

/// Uses [`FusedIterator`] default implementation.
///
/// [`FusedIterator`]: https://doc.rust-lang.org/core/iter/trait.FusedIterator.html
impl<I: FusedIterator> FusedIterator for PeekMoreIterator<I> {}

/// This enumeration provides errors which represent lack of success of the [`PeekMoreIterator`].
///
/// [`PeekMoreIterator`]: struct.PeekMoreIterator.html
#[derive(Debug, Eq, PartialEq)]
pub enum PeekMoreError {
    /// This error case will be returned if we try to move to an element, but it has already been
    /// consumed by the iterator.
    /// We can only peek at elements which haven't been consumed.
    ElementHasBeenConsumed,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn readme_example() {
        let range10 = 0..11;
        let mut peekable = range10.peekmore();

        // Peek at the first element
        let peek_first = peekable.peek();
        assert_eq!(*peek_first.unwrap(), 0);

        let peek_first_redux = peekable.peek_nth(0);
        assert_eq!(*peek_first_redux.unwrap(), 0);

        // Peek at the 10th (index) element
        let peek_tenth = peekable.peek_nth(10);
        assert_eq!(*peek_tenth.unwrap(), 10);

        // Consume the 10th element
        let tenth = peekable.nth(10);
        assert_eq!(tenth.unwrap(), 10);

        // Show that there are no more elements
        assert_eq!(peekable.peek(), None);
        assert_eq!(peekable.next(), None);
    }

    #[test]
    fn peek_forward_with_reassignment() {
        let iterable = [1, 2, 3, 4];

        let mut peek = iterable.iter().peekmore();

        assert_eq!(peek.peek(), Some(&&1));

        let peek = peek.advance_cursor();
        assert_eq!(peek.peek(), Some(&&2));

        let peek = peek.advance_cursor();
        assert_eq!(peek.peek(), Some(&&3));

        let peek = peek.advance_cursor();
        assert_eq!(peek.peek(), Some(&&4));

        let peek = peek.advance_cursor();
        assert_eq!(peek.peek(), None);
    }

    #[test]
    fn peek_forward_without_reassignment_separately_advance_and_peek() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore();

        assert_eq!(iter.peek(), Some(&&1));

        let v2 = iter.advance_cursor().peek();
        assert_eq!(v2, Some(&&2));

        let v3 = iter.advance_cursor().peek();
        assert_eq!(v3, Some(&&3));

        let v4 = iter.advance_cursor().peek();
        assert_eq!(v4, Some(&&4));

        let v5 = iter.advance_cursor().peek();
        assert_eq!(v5, None);
    }

    #[test]
    fn peek_forward_without_reassignment_advance_and_peek_combined() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore();

        let v1 = iter.peek();
        assert_eq!(v1, Some(&&1));

        let v2 = iter.peek_next();
        assert_eq!(v2, Some(&&2));

        let v3 = iter.peek_next();
        assert_eq!(v3, Some(&&3));

        let v4 = iter.peek_next();
        assert_eq!(v4, Some(&&4));

        let v5 = iter.peek_next();
        assert_eq!(v5, None);
    }

    #[test]
    fn peek_forward_without_reassignment_advance_and_peek_combined_and_reset_view() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore();

        let v1 = iter.peek();
        assert_eq!(v1, Some(&&1));

        let v2 = iter.peek_next();
        assert_eq!(v2, Some(&&2));

        iter.reset_cursor();
        let v1again = iter.peek();
        assert_eq!(v1again, Some(&&1));

        let v2again = iter.peek_next();
        assert_eq!(v2again, Some(&&2));

        let v3 = iter.peek_next();
        assert_eq!(v3, Some(&&3));

        let v4 = iter.peek_next();
        assert_eq!(v4, Some(&&4));

        let v5 = iter.peek_next();
        assert_eq!(v5, None);
    }

    #[test]
    fn empty() {
        let iterable: [i32; 0] = [];

        let mut iter = iterable.iter().peekmore();

        assert_eq!(iter.peek(), None);

        let none = iter.peek_next();
        assert_eq!(none, None);

        let iter = iter.advance_cursor();
        assert_eq!(iter.peek(), None);
        assert_eq!(iter.peek_next(), None);
    }

    #[test]
    fn test_with_consume() {
        let iterable = "123".chars();

        let mut iter = iterable.peekmore();
        assert_eq!(iter.peek(), Some(&core::char::from_digit(1, 10).unwrap()));
        assert_eq!(
            iter.peek_next(),
            Some(&core::char::from_digit(2, 10).unwrap())
        );
        assert_eq!(
            iter.peek_next(),
            Some(&core::char::from_digit(3, 10).unwrap())
        );
        assert_eq!(iter.peek_next(), None);
        assert_eq!(iter.next(), Some(core::char::from_digit(1, 10).unwrap()));
        assert_eq!(iter.peek(), None);
        assert_eq!(iter.peek_next(), None);
        assert_eq!(iter.next(), Some(core::char::from_digit(2, 10).unwrap()));
        assert_eq!(iter.peek(), None);
        assert_eq!(iter.peek_next(), None);
        assert_eq!(iter.next(), Some(core::char::from_digit(3, 10).unwrap()));
        assert_eq!(iter.next(), None);
        assert_eq!(iter.peek_next(), None);
    }

    #[test]
    fn test_with_consume_and_reset() {
        let iterable = "456".chars();

        let mut iter = iterable.peekmore();
        assert_eq!(iter.peek(), Some(&core::char::from_digit(4, 10).unwrap()));
        assert_eq!(
            iter.peek_next(),
            Some(&core::char::from_digit(5, 10).unwrap())
        );
        assert_eq!(
            iter.peek_next(),
            Some(&core::char::from_digit(6, 10).unwrap())
        );
        assert_eq!(iter.peek_next(), None);
        assert_eq!(iter.next(), Some(core::char::from_digit(4, 10).unwrap()));
        iter.reset_cursor();

        assert_eq!(iter.peek(), Some(&core::char::from_digit(5, 10).unwrap()));
        assert_eq!(
            iter.peek_next(),
            Some(&core::char::from_digit(6, 10).unwrap())
        );

        assert_eq!(iter.next(), Some(core::char::from_digit(5, 10).unwrap()));
        assert_eq!(iter.next(), Some(core::char::from_digit(6, 10).unwrap()));
        assert_eq!(iter.next(), None);
        assert_eq!(iter.peek_next(), None);
    }

    #[test]
    fn check_peek_window_moves_with_consume() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore();

        let v1 = iter.peek();
        assert_eq!(v1, Some(&&1));

        let v1c = iter.next();
        assert_eq!(v1c, Some(&1));

        let v2 = iter.peek();
        assert_eq!(v2, Some(&&2));

        let v2c = iter.next();
        assert_eq!(v2c, Some(&2));

        let v3 = iter.peek();
        assert_eq!(v3, Some(&&3));

        iter.reset_cursor();

        let v3 = iter.peek();
        assert_eq!(v3, Some(&&3));

        let v3c = iter.next();
        assert_eq!(v3c, Some(&3));

        let v4c = iter.next();
        assert_eq!(v4c, Some(&4));

        let v5 = iter.peek();
        assert_eq!(v5, None);

        let v5c = iter.next();
        assert_eq!(v5c, None);
    }

    #[test]
    fn check_advance_separately() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore(); // j -> 1

        assert_eq!(iter.cursor(), 0);
        assert_eq!(iter.peek(), Some(&&1));

        iter.advance_cursor(); // j -> 2
        assert_eq!(iter.cursor(), 1);

        iter.advance_cursor(); // j -> 3
        assert_eq!(iter.cursor(), 2);

        iter.advance_cursor(); // j -> 4
        assert_eq!(iter.cursor(), 3);

        let v4 = iter.peek();
        assert_eq!(v4, Some(&&4));
    }

    #[test]
    fn check_advance_chain() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore(); // j -> 1

        assert_eq!(iter.cursor(), 0);

        iter.advance_cursor() // j -> 2
            .advance_cursor() // j -> 3
            .advance_cursor(); // j -> 4

        let v4 = iter.peek();
        assert_eq!(v4, Some(&&4));
    }

    #[test]
    fn check_move_previous() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore(); // j -> 1

        assert_eq!(iter.cursor(), 0);
        assert_eq!(iter.peek(), Some(&&1));

        iter.advance_cursor(); // j -> 2
        assert_eq!(iter.cursor(), 1);

        let _ = iter.move_cursor_back(); // j -> 1
        assert_eq!(iter.cursor(), 0);

        iter.advance_cursor(); // j -> 2
        assert_eq!(iter.cursor(), 1);

        let _ = iter.move_cursor_back(); // j -> 1
        assert_eq!(iter.cursor(), 0);

        iter.advance_cursor(); // j -> 2
        assert_eq!(iter.cursor(), 1);

        iter.advance_cursor() // j -> 3
            .advance_cursor(); // j -> 4

        assert_eq!(iter.cursor(), 3);

        let v4 = iter.peek();
        assert_eq!(v4, Some(&&4));

        let _ = iter.move_cursor_back().and_then(|it| {
            it.move_cursor_back() // j -> 3
                .and_then(|it| {
                    it.move_cursor_back() // j -> 2
                        .and_then(|it| it.move_cursor_back())
                })
        }); // j -> 1

        let v1 = iter.peek();
        assert_eq!(v1, Some(&&1));

        let prev = iter.move_cursor_back();
        assert!(prev.is_err());

        let v1 = iter.peek();
        assert_eq!(v1, Some(&&1));
    }

    #[test]
    fn test_with_inherited_feature_count() {
        let iterable = [1, 2, 3];
        let mut iter = iterable.iter().peekmore();

        iter.advance_cursor();
        let second = iter.peek().unwrap();
        assert_eq!(second, &&2);

        let consume_first = iter.next().unwrap();
        assert_eq!(consume_first, &1);

        let count = iter.count();
        assert_eq!(count, 2);
    }

    #[test]
    fn peek_previous() {
        let iterable = [1, 2, 3];
        let mut iter = iterable.iter().peekmore(); // j = 1

        iter.advance_cursor(); // j = 2
        iter.advance_cursor(); // j = 3
        let value = iter.peek().unwrap(); // 3
        assert_eq!(value, &&3);

        let peek = iter.peek_previous(); // 2
        assert_eq!(peek.unwrap(), Some(&&2));
        assert_eq!(iter.cursor(), 1);

        let peek = iter.peek_previous(); // 1
        assert_eq!(peek.unwrap(), Some(&&1));
        assert_eq!(iter.cursor(), 0);

        let peek = iter.peek_previous();
        assert_eq!(peek, Err(PeekMoreError::ElementHasBeenConsumed));
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn peek_previous_beyond_none() {
        let iterable = [1];
        let mut iter = iterable.iter().peekmore(); // j = 1
        assert_eq!(iter.cursor(), 0);

        iter.advance_cursor(); // j = None (1)
        let peek = iter.peek();
        assert_eq!(peek, None);
        assert_eq!(iter.cursor(), 1);

        iter.advance_cursor(); // j = None (2)
        let peek = iter.peek();
        assert_eq!(peek, None);
        assert_eq!(iter.cursor(), 2);

        iter.advance_cursor(); // j = None (3)
        let peek = iter.peek(); // current
        assert_eq!(peek, None);
        assert_eq!(iter.cursor(), 3);

        let peek = iter.peek_previous(); // None (2)
        assert_eq!(peek.unwrap(), None);
        assert_eq!(iter.cursor(), 2);

        let peek = iter.peek_previous(); // None (1)
        assert_eq!(peek.unwrap(), None);
        assert_eq!(iter.cursor(), 1);

        let peek = iter.peek_previous(); // 1
        assert_eq!(peek.unwrap(), Some(&&1));
        assert_eq!(iter.cursor(), 0);

        let peek = iter.peek_previous();
        assert_eq!(peek, Err(PeekMoreError::ElementHasBeenConsumed));
        assert_eq!(iter.cursor(), 0);

        let peek = iter.peek_previous();
        assert_eq!(peek, Err(PeekMoreError::ElementHasBeenConsumed));
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_move_forward() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_by(3);

        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);

        let _ = iter.advance_cursor_by(3);
        let peek = iter.peek();
        assert_eq!(peek, None);
        assert_eq!(iter.cursor(), 6);
    }

    #[test]
    fn check_move_backward() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_by(3);

        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);

        let result = iter.move_cursor_back_by(2);
        assert!(result.is_ok());
        let peek = iter.peek();
        assert_eq!(peek, Some(&&2));
        assert_eq!(iter.cursor(), 1);

        let result = iter.move_cursor_back_by(1);
        assert!(result.is_ok());
        let peek = iter.peek();
        assert_eq!(peek, Some(&&1));
        assert_eq!(iter.cursor(), 0);

        let result = iter.move_cursor_back_by(1);
        assert!(result.is_err());
        let peek = iter.peek();
        assert_eq!(peek, Some(&&1));
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_move_backward_beyond_consumed_verify_cursor_position() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_by(3);

        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);

        let result = iter.move_cursor_back_by(5);
        assert!(result.is_err());
        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);
    }

    #[test]
    fn check_move_backward_or_reset() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_by(3);

        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);

        let _ = iter.move_cursor_back_or_reset(2);
        let peek = iter.peek();
        assert_eq!(peek, Some(&&2));
        assert_eq!(iter.cursor(), 1);

        let _ = iter.move_cursor_back_or_reset(1);
        let peek = iter.peek();
        assert_eq!(peek, Some(&&1));
        assert_eq!(iter.cursor(), 0);

        let _ = iter.move_cursor_back_or_reset(1);
        let peek = iter.peek();
        assert_eq!(peek, Some(&&1));
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_move_backward_or_reset_beyond_consumed_verify_cursor_position() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_by(3);

        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);

        let _ = iter.move_cursor_back_or_reset(5);
        let peek = iter.peek();
        assert_eq!(peek, Some(&&1));
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_move_backward_or_reset_empty() {
        let iterable = "".chars();

        let mut iter = iterable.peekmore();

        assert_eq!(iter.peek(), None);
        assert_eq!(iter.cursor(), 0);

        let _ = iter.move_cursor_back_or_reset(5);

        assert_eq!(iter.peek(), None);
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_peek_forward() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let peek = iter.peek_forward(3);

        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);

        let peek = iter.peek_forward(3);
        assert_eq!(peek, None);
        assert_eq!(iter.cursor(), 6);
    }

    #[test]
    fn check_peek_backward() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_by(3);

        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);

        let result = iter.peek_backward(2);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), Some(&&2));
        assert_eq!(iter.cursor(), 1);

        let result = iter.peek_backward(1);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), Some(&&1));
        assert_eq!(iter.cursor(), 0);

        let result = iter.peek_backward(1);
        assert!(result.is_err());
        let peek = iter.peek();
        assert_eq!(peek, Some(&&1));
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_peek_backward_beyond_consumed_verify_cursor_position() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_by(3);

        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);

        let result = iter.peek_backward(5);
        assert!(result.is_err());
        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);
    }

    #[test]
    fn check_peek_backward_or_first_beyond_consumed_verify_cursor_position() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_by(3);

        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);

        let peek = iter.peek_backward_or_first(5);
        assert_eq!(peek, Some(&&1));
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_peek_backward_or_first_empty() {
        let iterable = "".chars();

        let mut iter = iterable.peekmore();

        assert_eq!(iter.peek(), None);
        assert_eq!(iter.cursor(), 0);

        let peek = iter.peek_backward_or_first(5);

        assert_eq!(peek, None);
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_move_forward_while() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_while(|i| **i.unwrap() != 3);

        let peek = iter.peek();
        assert_eq!(peek, Some(&&2));
        assert_eq!(iter.cursor(), 1);
    }

    #[test]
    fn check_move_forward_while_empty() {
        let iterable: [i32; 0] = [];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_while(|i| if let Some(i) = i { **i != 3 } else { false });

        let peek = iter.peek();
        assert_eq!(peek, None);
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_move_forward_while_some() {
        let iterable = [1, 2, 3, 4];
        let mut iter = iterable.iter().peekmore();

        let _ = iter.advance_cursor_while(|i| i.is_some());

        let peek = iter.peek();
        assert_eq!(peek, Some(&&4));
        assert_eq!(iter.cursor(), 3);
    }

    #[test]
    fn check_peek_nth() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore();

        assert_eq!(iter.peek_nth(0), Some(&&1));
        assert_eq!(iter.cursor(), 0);
        assert_eq!(iter.peek_nth(1), Some(&&2));
        assert_eq!(iter.cursor(), 0);
        assert_eq!(iter.peek_nth(2), Some(&&3));
        assert_eq!(iter.cursor(), 0);
        assert_eq!(iter.peek_nth(3), Some(&&4));
        assert_eq!(iter.cursor(), 0);
        assert_eq!(iter.peek_nth(4), None);
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_peek_nth_empty() {
        let iterable: [i32; 0] = [];

        let mut iter = iterable.iter().peekmore();

        assert_eq!(iter.peek_nth(0), None);
        assert_eq!(iter.cursor(), 0);
        assert_eq!(iter.peek_nth(1), None);
        assert_eq!(iter.cursor(), 0);
    }

    #[test]
    fn check_move_nth() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore();

        iter.move_nth(20);
        assert_eq!(iter.peek_nth(0), Some(&&1));
        assert_eq!(iter.cursor(), 20);
        assert_eq!(iter.peek(), None);

        iter.move_nth(0);
        assert_eq!(iter.peek(), Some(&&1));

        iter.move_nth(3);
        assert_eq!(iter.peek(), Some(&&4));
    }

    #[test]
    fn check_move_nth_empty() {
        let iterable: [i32; 0] = [];

        let mut iter = iterable.iter().peekmore();

        iter.move_nth(0);
        assert_eq!(iter.cursor(), 0);

        iter.move_nth(10);
        assert_eq!(iter.cursor(), 10);
    }

    #[test]
    fn truncate_iterator_to_cursor_is_noop_when_queue_is_empty_from_no_peeking() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore();

        assert!(iter.queue.is_empty());

        iter.truncate_iterator_to_cursor();

        assert!(iter.queue.is_empty());
        assert_eq!(iter.peek(), Some(&&1));
        assert!(!iter.queue.is_empty());
    }

    #[test]
    fn truncate_iterator_to_cursor_is_noop_when_queue_is_empty_from_iteration() {
        let iterable = [1, 2, 3, 4];

        let mut iter = iterable.iter().peekmore();

        assert!(iter.queue.is_empty());

        iter.peek_forward(2);
        iter.next();
        iter.next();
        iter.next();

        assert!(iter.queue.is_empty());

        iter.truncate_iterator_to_cursor();

        assert!(iter.queue.is_empty());
        assert_eq!(iter.peek(), Some(&&4));
        assert!(!iter.queue.is_empty());
    }

    #[test]
    fn truncate_to_iterator_fill_queue() {
        let mut iter = [0, 1, 2, 3].iter().peekmore();
        iter.advance_cursor();
        iter.truncate_iterator_to_cursor();

        let value = **iter.peek().unwrap();

        assert_eq!(value, 1);
    }

    #[test]
    fn truncate_to_iterator_on_empty_collection() {
        let mut iter = core::iter::empty::<i32>().peekmore();
        iter.advance_cursor();
        assert_eq!(iter.cursor, 1);

        iter.truncate_iterator_to_cursor();
        assert_eq!(iter.cursor, 0);

        assert!(iter.peek().is_none());
    }

    #[test]
    fn truncate_to_iterator_on_single_element_collection() {
        let mut iter = core::iter::once(0).peekmore();
        assert_eq!(*iter.peek().unwrap(), 0);
        assert_eq!(iter.cursor, 0);

        iter.advance_cursor(); // starts at 0, so now is 1 (i.e. second element so None)
        assert_eq!(iter.cursor, 1);
        assert!(iter.peek().is_none());

        iter.truncate_iterator_to_cursor();
        assert_eq!(iter.cursor, 0);

        assert!(iter.peek().is_none());
    }

    #[test]
    fn truncate_to_iterator_cursor_and_queue_equal_length() {
        let mut iter = [0, 1, 2, 3].iter().peekmore();
        iter.peek();
        iter.advance_cursor();
        iter.truncate_iterator_to_cursor();

        assert_eq!(iter.next(), Some(&1));
        assert_eq!(iter.next(), Some(&2));
        assert_eq!(iter.next(), Some(&3));
        assert_eq!(iter.next(), None);
    }
}