-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
213 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,242 @@ | ||
//! This crate contains an iterator which allows you to fully peek forward any number of elements. | ||
|
||
use std::collections::VecDeque; | ||
use std::iter::FusedIterator; | ||
|
||
/// A trait for an interator which allows you to fully peek forward any number of elements. | ||
#[derive(Clone, Debug)] | ||
pub struct FullyPeekable<I: Iterator> { | ||
pub struct FullyPeekableIterator<I: Iterator> { | ||
iter: I, | ||
queue: VecDeque<I::Item>, | ||
queue: VecDeque<I::Item> | ||
} | ||
|
||
/// Create a new FullyPeekable iterator from an existing iterator. | ||
impl<I: Iterator> FullyPeekable<I> { | ||
pub(crate) fn new(iter: I) -> FullyPeekable<I> { | ||
FullyPeekable { | ||
/// Create a new fully-peekable iterator from an existing iterator. | ||
impl<I: Iterator> FullyPeekableIterator<I> { | ||
fn new(iter: I) -> FullyPeekableIterator<I> { | ||
FullyPeekableIterator { | ||
iter, | ||
queue: VecDeque::new(), | ||
queue: VecDeque::new() | ||
} | ||
} | ||
} | ||
|
||
/// FullyPeekable will return elements that have been previously peeked before advancing. | ||
impl<I: Iterator> Iterator for FullyPeekable<I> { | ||
/// Implementation of the typical iterator methods on the fully-peekable iterator. | ||
impl<I: Iterator> Iterator for FullyPeekableIterator<I> { | ||
type Item = I::Item; | ||
|
||
/// Returns the next value which may advance the iterator. | ||
#[inline] | ||
fn next(&mut self) -> Option<Self::Item> { | ||
self.queue.pop_front().or_else(|| self.iter.next()) | ||
} | ||
|
||
#[inline] | ||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
todo!() | ||
} | ||
|
||
#[inline] | ||
fn count(self) -> usize { | ||
todo!() | ||
} | ||
|
||
#[inline] | ||
fn last(mut self) -> Option<I::Item> { | ||
todo!() | ||
} | ||
|
||
#[inline] | ||
fn nth(&mut self, n: usize) -> Option<I::Item> { | ||
todo!() | ||
} | ||
} | ||
|
||
impl<I: Iterator> FullyPeekable<I> { | ||
// TODO: Implement `DoubleEndedIterator` for `FullyPeekableIterator`? | ||
|
||
impl<I: ExactSizeIterator> ExactSizeIterator for FullyPeekableIterator<I> {} | ||
|
||
impl<I: FusedIterator> FusedIterator for FullyPeekableIterator<I> {} | ||
|
||
impl<I: Iterator> FullyPeekableIterator<I> { | ||
|
||
/// Test if the iterator has another element to yield. May advance the underlying iterator. | ||
#[inline] | ||
pub fn has_next(&mut self) -> bool { | ||
self.peek().is_some() | ||
} | ||
|
||
/// Peek forward to an arbitrary element without advancing the iterator. | ||
#[inline] | ||
pub fn lift(&mut self, index: usize) -> Option<&I::Item> { | ||
while self.queue.len() <= index + 1 { | ||
match self.iter.next() { | ||
Some(item) => self.queue.push_back(item), | ||
None => break | ||
} | ||
}; | ||
self.queue.get(index) | ||
} | ||
|
||
/// Peek forward to an arbitrary element without advancing the iterator. | ||
#[inline] | ||
pub fn lift_mut(&mut self, index: usize) -> Option<&mut I::Item> { | ||
while self.queue.len() <= index + 1 { | ||
match self.iter.next() { | ||
Some(item) => self.queue.push_back(item), | ||
None => break | ||
} | ||
}; | ||
self.queue.get_mut(index) | ||
} | ||
|
||
/// Peek forward to the next element without advancing the iterator. | ||
#[inline] | ||
pub fn peek(&mut self) -> Option<&I::Item> { | ||
let iter = &mut self.iter; | ||
self.queue.get(0) match { | ||
self.lift(0) | ||
} | ||
|
||
/// Peek forward to the next element marking it as mutable without advancing the iterator. | ||
#[inline] | ||
pub fn peek_mut(&mut self) -> Option<&mut I::Item> { | ||
self.lift_mut(0) | ||
} | ||
|
||
/// Consume and return the next value of this iterator if a condition is true. | ||
#[inline] | ||
pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> { | ||
match self.next() { | ||
Some(matched) if func(&matched) => Some(matched), | ||
Some(other) => { | ||
self.queue.push_front(other); | ||
None | ||
} | ||
other => None | ||
} | ||
} | ||
|
||
/// Consume and return the next item if it is equal to `expected`. | ||
#[inline] | ||
pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item> | ||
where | ||
T: ?Sized, | ||
I::Item: PartialEq<T>, | ||
{ | ||
self.next_if(|next| next == expected) | ||
} | ||
} | ||
|
||
/// A trait for an iterator which allows you to fully peek forward any number of elements. | ||
pub trait IntoFullyPeekableIterator<I> | ||
where | ||
I: Iterator, | ||
{ | ||
/// Return a fully peekable iterator. | ||
fn fully_peekable(self) -> FullyPeekableIterator<I>; | ||
} | ||
|
||
/// Add a fully-peekable iterator implementation to any iterator implicitly. | ||
impl<I, T> IntoFullyPeekableIterator<I> for I | ||
where | ||
I: Iterator<Item = T>, | ||
{ | ||
/// Return a fully peekable iterator. | ||
fn fully_peekable(self) -> FullyPeekableIterator<I> { | ||
FullyPeekableIterator::new(self) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::FullyPeekable; | ||
use crate::{FullyPeekableIterator, IntoFullyPeekableIterator}; | ||
|
||
#[test] | ||
fn the_class_returns_elements_like_an_iterator_when_using_next() { | ||
let iter = vec![1, 2].into_iter(); | ||
let mut peekable = FullyPeekableIterator::new(iter); | ||
assert_eq!(peekable.next(), Some(1)); | ||
assert_eq!(peekable.next(), Some(2)); | ||
assert_eq!(peekable.next(), None); | ||
} | ||
|
||
#[test] | ||
fn it_uses_has_next_to_determine_if_there_are_more_elements() { | ||
let iter = vec![1, 2].into_iter(); | ||
let mut peekable = FullyPeekableIterator::new(iter); | ||
assert_eq!(peekable.has_next(), true); | ||
assert_eq!(peekable.next(), Some(1)); | ||
assert_eq!(peekable.has_next(), true); | ||
assert_eq!(peekable.next(), Some(2)); | ||
assert_eq!(peekable.has_next(), false); | ||
assert_eq!(peekable.next(), None); | ||
assert_eq!(peekable.has_next(), false); | ||
} | ||
|
||
#[test] | ||
fn it_can_lift_elements_without_advancing() { | ||
let iter = vec![1, 2].into_iter(); | ||
let mut peekable = FullyPeekableIterator::new(iter); | ||
assert_eq!(peekable.lift(0), Some(&1)); | ||
assert_eq!(peekable.lift(1), Some(&2)); | ||
assert_eq!(peekable.lift(2), None); | ||
assert_eq!(peekable.next(), Some(1)); | ||
assert_eq!(peekable.next(), Some(2)); | ||
assert_eq!(peekable.peek(), None); | ||
} | ||
|
||
#[test] | ||
fn it_can_peek_at_the_next_element_without_advancing() { | ||
let iter = vec![1, 2].into_iter(); | ||
let mut peekable = iter.fully_peekable(); | ||
assert_eq!(peekable.peek(), Some(&1)); | ||
assert_eq!(peekable.next(), Some(1)); | ||
assert_eq!(peekable.peek(), Some(&2)); | ||
assert_eq!(peekable.next(), Some(2)); | ||
assert_eq!(peekable.peek(), None); | ||
assert_eq!(peekable.next(), None); | ||
} | ||
|
||
#[test] | ||
fn it_can_lift_elements_without_advancing_mut() { | ||
let iter = vec![1, 2].into_iter(); | ||
let mut peekable = FullyPeekableIterator::new(iter); | ||
assert_eq!(peekable.lift_mut(0), Some(&mut 1)); | ||
assert_eq!(peekable.lift_mut(1), Some(&mut 2)); | ||
assert_eq!(peekable.lift_mut(2), None); | ||
assert_eq!(peekable.next(), Some(1)); | ||
assert_eq!(peekable.next(), Some(2)); | ||
assert_eq!(peekable.peek(), None); | ||
} | ||
|
||
#[test] | ||
fn it_can_peek_at_the_next_element_without_advancing_mut() { | ||
let iter = vec![1, 2].into_iter(); | ||
let mut peekable = iter.fully_peekable(); | ||
assert_eq!(peekable.peek_mut(), Some(&mut 1)); | ||
assert_eq!(peekable.next(), Some(1)); | ||
assert_eq!(peekable.peek_mut(), Some(&mut 2)); | ||
assert_eq!(peekable.next(), Some(2)); | ||
assert_eq!(peekable.peek_mut(), None); | ||
assert_eq!(peekable.next(), None); | ||
} | ||
|
||
#[test] | ||
fn it_can_return_the_next_element_if_a_predicate_is_true() { | ||
let iter = vec![1, 2].into_iter(); | ||
let mut peekable = iter.fully_peekable(); | ||
assert_eq!(peekable.next_if(|next| next == &0), None); | ||
assert_eq!(peekable.next_if(|next| next == &1), Some(1)); | ||
assert_eq!(peekable.next_if(|next| next == &1), None); | ||
assert_eq!(peekable.next_if(|next| next == &2), Some(2)); | ||
assert_eq!(peekable.has_next(), false); | ||
} | ||
|
||
#[test] | ||
fn it_works() { | ||
let iter: Vec<i32> = vec![1, 2, 3]; | ||
let peekable = FullyPeekable::new(iter.into_iter()); | ||
fn it_can_return_the_next_element_if_it_is_equal_to_a_supplied_value() { | ||
let iter = vec![1, 2].into_iter(); | ||
let mut peekable = iter.fully_peekable(); | ||
assert_eq!(peekable.next_if_eq(&0), None); | ||
assert_eq!(peekable.next_if_eq(&1), Some(1)); | ||
assert_eq!(peekable.next_if_eq(&1), None); | ||
assert_eq!(peekable.next_if_eq(&2), Some(2)); | ||
assert_eq!(peekable.has_next(), false); | ||
} | ||
} |