Skip to content

Commit

Permalink
Merge pull request #91 from aj-bagwell/master
Browse files Browse the repository at this point in the history
add factor_iter() and iter() methods
  • Loading branch information
cuviper committed Feb 10, 2024
2 parents 361af9e + 499b9ed commit 254fbf6
Show file tree
Hide file tree
Showing 2 changed files with 461 additions and 157 deletions.
317 changes: 317 additions & 0 deletions src/iterator.rs
@@ -0,0 +1,317 @@
use super::{for_both, Either, Left, Right};
use core::iter;

macro_rules! wrap_either {
($value:expr => $( $tail:tt )*) => {
match $value {
Left(inner) => inner.map(Left) $($tail)*,
Right(inner) => inner.map(Right) $($tail)*,
}
};
}

/// Iterator that maps left or right iterators to corresponding `Either`-wrapped items.
///
/// This struct is created by the [`Either::factor_into_iter`],
/// [`factor_iter`][Either::factor_iter],
/// and [`factor_iter_mut`][Either::factor_iter_mut] methods.
#[derive(Clone, Debug)]
pub struct IterEither<L, R> {
inner: Either<L, R>,
}

impl<L, R> IterEither<L, R> {
pub(crate) fn new(inner: Either<L, R>) -> Self {
IterEither { inner }
}
}

impl<L, R, A> Extend<A> for Either<L, R>
where
L: Extend<A>,
R: Extend<A>,
{
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = A>,
{
for_both!(*self, ref mut inner => inner.extend(iter))
}
}

/// `Either<L, R>` is an iterator if both `L` and `R` are iterators.
impl<L, R> Iterator for Either<L, R>
where
L: Iterator,
R: Iterator<Item = L::Item>,
{
type Item = L::Item;

fn next(&mut self) -> Option<Self::Item> {
for_both!(*self, ref mut inner => inner.next())
}

fn size_hint(&self) -> (usize, Option<usize>) {
for_both!(*self, ref inner => inner.size_hint())
}

fn fold<Acc, G>(self, init: Acc, f: G) -> Acc
where
G: FnMut(Acc, Self::Item) -> Acc,
{
for_both!(self, inner => inner.fold(init, f))
}

fn for_each<F>(self, f: F)
where
F: FnMut(Self::Item),
{
for_both!(self, inner => inner.for_each(f))
}

fn count(self) -> usize {
for_both!(self, inner => inner.count())
}

fn last(self) -> Option<Self::Item> {
for_both!(self, inner => inner.last())
}

fn nth(&mut self, n: usize) -> Option<Self::Item> {
for_both!(*self, ref mut inner => inner.nth(n))
}

fn collect<B>(self) -> B
where
B: iter::FromIterator<Self::Item>,
{
for_both!(self, inner => inner.collect())
}

fn partition<B, F>(self, f: F) -> (B, B)
where
B: Default + Extend<Self::Item>,
F: FnMut(&Self::Item) -> bool,
{
for_both!(self, inner => inner.partition(f))
}

fn all<F>(&mut self, f: F) -> bool
where
F: FnMut(Self::Item) -> bool,
{
for_both!(*self, ref mut inner => inner.all(f))
}

fn any<F>(&mut self, f: F) -> bool
where
F: FnMut(Self::Item) -> bool,
{
for_both!(*self, ref mut inner => inner.any(f))
}

fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
for_both!(*self, ref mut inner => inner.find(predicate))
}

fn find_map<B, F>(&mut self, f: F) -> Option<B>
where
F: FnMut(Self::Item) -> Option<B>,
{
for_both!(*self, ref mut inner => inner.find_map(f))
}

fn position<P>(&mut self, predicate: P) -> Option<usize>
where
P: FnMut(Self::Item) -> bool,
{
for_both!(*self, ref mut inner => inner.position(predicate))
}
}

impl<L, R> DoubleEndedIterator for Either<L, R>
where
L: DoubleEndedIterator,
R: DoubleEndedIterator<Item = L::Item>,
{
fn next_back(&mut self) -> Option<Self::Item> {
for_both!(*self, ref mut inner => inner.next_back())
}

// TODO(MSRV): This was stabilized in Rust 1.37
// fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
// for_both!(*self, ref mut inner => inner.nth_back(n))
// }

fn rfold<Acc, G>(self, init: Acc, f: G) -> Acc
where
G: FnMut(Acc, Self::Item) -> Acc,
{
for_both!(self, inner => inner.rfold(init, f))
}

fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
for_both!(*self, ref mut inner => inner.rfind(predicate))
}
}

impl<L, R> ExactSizeIterator for Either<L, R>
where
L: ExactSizeIterator,
R: ExactSizeIterator<Item = L::Item>,
{
fn len(&self) -> usize {
for_both!(*self, ref inner => inner.len())
}
}

impl<L, R> iter::FusedIterator for Either<L, R>
where
L: iter::FusedIterator,
R: iter::FusedIterator<Item = L::Item>,
{
}

impl<L, R> Iterator for IterEither<L, R>
where
L: Iterator,
R: Iterator,
{
type Item = Either<L::Item, R::Item>;

fn next(&mut self) -> Option<Self::Item> {
Some(map_either!(self.inner, ref mut inner => inner.next()?))
}

fn size_hint(&self) -> (usize, Option<usize>) {
for_both!(self.inner, ref inner => inner.size_hint())
}

fn fold<Acc, G>(self, init: Acc, f: G) -> Acc
where
G: FnMut(Acc, Self::Item) -> Acc,
{
wrap_either!(self.inner => .fold(init, f))
}

fn for_each<F>(self, f: F)
where
F: FnMut(Self::Item),
{
wrap_either!(self.inner => .for_each(f))
}

fn count(self) -> usize {
for_both!(self.inner, inner => inner.count())
}

fn last(self) -> Option<Self::Item> {
Some(map_either!(self.inner, inner => inner.last()?))
}

fn nth(&mut self, n: usize) -> Option<Self::Item> {
Some(map_either!(self.inner, ref mut inner => inner.nth(n)?))
}

fn collect<B>(self) -> B
where
B: iter::FromIterator<Self::Item>,
{
wrap_either!(self.inner => .collect())
}

fn partition<B, F>(self, f: F) -> (B, B)
where
B: Default + Extend<Self::Item>,
F: FnMut(&Self::Item) -> bool,
{
wrap_either!(self.inner => .partition(f))
}

fn all<F>(&mut self, f: F) -> bool
where
F: FnMut(Self::Item) -> bool,
{
wrap_either!(&mut self.inner => .all(f))
}

fn any<F>(&mut self, f: F) -> bool
where
F: FnMut(Self::Item) -> bool,
{
wrap_either!(&mut self.inner => .any(f))
}

fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
wrap_either!(&mut self.inner => .find(predicate))
}

fn find_map<B, F>(&mut self, f: F) -> Option<B>
where
F: FnMut(Self::Item) -> Option<B>,
{
wrap_either!(&mut self.inner => .find_map(f))
}

fn position<P>(&mut self, predicate: P) -> Option<usize>
where
P: FnMut(Self::Item) -> bool,
{
wrap_either!(&mut self.inner => .position(predicate))
}
}

impl<L, R> DoubleEndedIterator for IterEither<L, R>
where
L: DoubleEndedIterator,
R: DoubleEndedIterator,
{
fn next_back(&mut self) -> Option<Self::Item> {
Some(map_either!(self.inner, ref mut inner => inner.next_back()?))
}

// TODO(MSRV): This was stabilized in Rust 1.37
// fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
// Some(map_either!(self.inner, ref mut inner => inner.nth_back(n)?))
// }

fn rfold<Acc, G>(self, init: Acc, f: G) -> Acc
where
G: FnMut(Acc, Self::Item) -> Acc,
{
wrap_either!(self.inner => .rfold(init, f))
}

fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
wrap_either!(&mut self.inner => .rfind(predicate))
}
}

impl<L, R> ExactSizeIterator for IterEither<L, R>
where
L: ExactSizeIterator,
R: ExactSizeIterator,
{
fn len(&self) -> usize {
for_both!(self.inner, ref inner => inner.len())
}
}

impl<L, R> iter::FusedIterator for IterEither<L, R>
where
L: iter::FusedIterator,
R: iter::FusedIterator,
{
}

0 comments on commit 254fbf6

Please sign in to comment.