diff --git a/src/iterator.rs b/src/iterator.rs new file mode 100644 index 0000000..791d5ec --- /dev/null +++ b/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 { + inner: Either, +} + +impl IterEither { + pub(crate) fn new(inner: Either) -> Self { + IterEither { inner } + } +} + +impl Extend for Either +where + L: Extend, + R: Extend, +{ + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + for_both!(*self, ref mut inner => inner.extend(iter)) + } +} + +/// `Either` is an iterator if both `L` and `R` are iterators. +impl Iterator for Either +where + L: Iterator, + R: Iterator, +{ + type Item = L::Item; + + fn next(&mut self) -> Option { + for_both!(*self, ref mut inner => inner.next()) + } + + fn size_hint(&self) -> (usize, Option) { + for_both!(*self, ref inner => inner.size_hint()) + } + + fn fold(self, init: Acc, f: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + for_both!(self, inner => inner.fold(init, f)) + } + + fn for_each(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 { + for_both!(self, inner => inner.last()) + } + + fn nth(&mut self, n: usize) -> Option { + for_both!(*self, ref mut inner => inner.nth(n)) + } + + fn collect(self) -> B + where + B: iter::FromIterator, + { + for_both!(self, inner => inner.collect()) + } + + fn partition(self, f: F) -> (B, B) + where + B: Default + Extend, + F: FnMut(&Self::Item) -> bool, + { + for_both!(self, inner => inner.partition(f)) + } + + fn all(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.all(f)) + } + + fn any(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.any(f)) + } + + fn find

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

(&mut self, predicate: P) -> Option + where + P: FnMut(Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.position(predicate)) + } +} + +impl DoubleEndedIterator for Either +where + L: DoubleEndedIterator, + R: DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option { + 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 { + // for_both!(*self, ref mut inner => inner.nth_back(n)) + // } + + fn rfold(self, init: Acc, f: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + for_both!(self, inner => inner.rfold(init, f)) + } + + fn rfind

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.rfind(predicate)) + } +} + +impl ExactSizeIterator for Either +where + L: ExactSizeIterator, + R: ExactSizeIterator, +{ + fn len(&self) -> usize { + for_both!(*self, ref inner => inner.len()) + } +} + +impl iter::FusedIterator for Either +where + L: iter::FusedIterator, + R: iter::FusedIterator, +{ +} + +impl Iterator for IterEither +where + L: Iterator, + R: Iterator, +{ + type Item = Either; + + fn next(&mut self) -> Option { + Some(map_either!(self.inner, ref mut inner => inner.next()?)) + } + + fn size_hint(&self) -> (usize, Option) { + for_both!(self.inner, ref inner => inner.size_hint()) + } + + fn fold(self, init: Acc, f: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + wrap_either!(self.inner => .fold(init, f)) + } + + fn for_each(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 { + Some(map_either!(self.inner, inner => inner.last()?)) + } + + fn nth(&mut self, n: usize) -> Option { + Some(map_either!(self.inner, ref mut inner => inner.nth(n)?)) + } + + fn collect(self) -> B + where + B: iter::FromIterator, + { + wrap_either!(self.inner => .collect()) + } + + fn partition(self, f: F) -> (B, B) + where + B: Default + Extend, + F: FnMut(&Self::Item) -> bool, + { + wrap_either!(self.inner => .partition(f)) + } + + fn all(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + wrap_either!(&mut self.inner => .all(f)) + } + + fn any(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + wrap_either!(&mut self.inner => .any(f)) + } + + fn find

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

(&mut self, predicate: P) -> Option + where + P: FnMut(Self::Item) -> bool, + { + wrap_either!(&mut self.inner => .position(predicate)) + } +} + +impl DoubleEndedIterator for IterEither +where + L: DoubleEndedIterator, + R: DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option { + 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 { + // Some(map_either!(self.inner, ref mut inner => inner.nth_back(n)?)) + // } + + fn rfold(self, init: Acc, f: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + wrap_either!(self.inner => .rfold(init, f)) + } + + fn rfind

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + wrap_either!(&mut self.inner => .rfind(predicate)) + } +} + +impl ExactSizeIterator for IterEither +where + L: ExactSizeIterator, + R: ExactSizeIterator, +{ + fn len(&self) -> usize { + for_both!(self.inner, ref inner => inner.len()) + } +} + +impl iter::FusedIterator for IterEither +where + L: iter::FusedIterator, + R: iter::FusedIterator, +{ +} diff --git a/src/lib.rs b/src/lib.rs index 4c940fd..fc72c2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,6 @@ pub mod serde_untagged_optional; use core::convert::{AsMut, AsRef}; use core::fmt; use core::future::Future; -use core::iter; use core::ops::Deref; use core::ops::DerefMut; use core::pin::Pin; @@ -131,6 +130,18 @@ macro_rules! try_right { }; } +macro_rules! map_either { + ($value:expr, $pattern:pat => $result:expr) => { + match $value { + Left($pattern) => Left($result), + Right($pattern) => Right($result), + } + }; +} + +mod iterator; +pub use self::iterator::IterEither; + impl Clone for Either { fn clone(&self) -> Self { match self { @@ -508,6 +519,9 @@ impl Either { /// Convert the inner value to an iterator. /// + /// This requires the `Left` and `Right` iterators to have the same item type. + /// See [`factor_into_iter`][Either::factor_into_iter] to iterate different types. + /// /// ``` /// use either::*; /// @@ -522,10 +536,135 @@ impl Either { L: IntoIterator, R: IntoIterator, { - match self { - Left(l) => Left(l.into_iter()), - Right(r) => Right(r.into_iter()), - } + map_either!(self, inner => inner.into_iter()) + } + + /// Borrow the inner value as an iterator. + /// + /// This requires the `Left` and `Right` iterators to have the same item type. + /// See [`factor_iter`][Either::factor_iter] to iterate different types. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, &[u32]> = Left(vec![2, 3]); + /// let mut right: Either, _> = Right(&[4, 5][..]); + /// let mut all = vec![1]; + /// all.extend(left.iter()); + /// all.extend(right.iter()); + /// assert_eq!(all, vec![1, 2, 3, 4, 5]); + /// ``` + pub fn iter(&self) -> Either<<&L as IntoIterator>::IntoIter, <&R as IntoIterator>::IntoIter> + where + for<'a> &'a L: IntoIterator, + for<'a> &'a R: IntoIterator::Item>, + { + map_either!(self, inner => inner.into_iter()) + } + + /// Mutably borrow the inner value as an iterator. + /// + /// This requires the `Left` and `Right` iterators to have the same item type. + /// See [`factor_iter_mut`][Either::factor_iter_mut] to iterate different types. + /// + /// ``` + /// use either::*; + /// + /// let mut left: Either<_, &mut [u32]> = Left(vec![2, 3]); + /// for l in left.iter_mut() { + /// *l *= *l + /// } + /// assert_eq!(left, Left(vec![4, 9])); + /// + /// let mut inner = [4, 5]; + /// let mut right: Either, _> = Right(&mut inner[..]); + /// for r in right.iter_mut() { + /// *r *= *r + /// } + /// assert_eq!(inner, [16, 25]); + /// ``` + pub fn iter_mut( + &mut self, + ) -> Either<<&mut L as IntoIterator>::IntoIter, <&mut R as IntoIterator>::IntoIter> + where + for<'a> &'a mut L: IntoIterator, + for<'a> &'a mut R: IntoIterator::Item>, + { + map_either!(self, inner => inner.into_iter()) + } + + /// Converts an `Either` of `Iterator`s to be an `Iterator` of `Either`s + /// + /// Unlike [`into_iter`][Either::into_iter], this does not require the + /// `Left` and `Right` iterators to have the same item type. + /// + /// ``` + /// use either::*; + /// let left: Either<_, Vec> = Left(&["hello"]); + /// assert_eq!(left.factor_into_iter().next(), Some(Left(&"hello"))); + + /// let right: Either<&[&str], _> = Right(vec![0, 1]); + /// assert_eq!(right.factor_into_iter().collect::>(), vec![Right(0), Right(1)]); + /// + /// ``` + // TODO(MSRV): doc(alias) was stabilized in Rust 1.48 + // #[doc(alias = "transpose")] + pub fn factor_into_iter(self) -> IterEither + where + L: IntoIterator, + R: IntoIterator, + { + IterEither::new(map_either!(self, inner => inner.into_iter())) + } + + /// Borrows an `Either` of `Iterator`s to be an `Iterator` of `Either`s + /// + /// Unlike [`iter`][Either::iter], this does not require the + /// `Left` and `Right` iterators to have the same item type. + /// + /// ``` + /// use either::*; + /// let left: Either<_, Vec> = Left(["hello"]); + /// assert_eq!(left.factor_iter().next(), Some(Left(&"hello"))); + + /// let right: Either<[&str; 2], _> = Right(vec![0, 1]); + /// assert_eq!(right.factor_iter().collect::>(), vec![Right(&0), Right(&1)]); + /// + /// ``` + pub fn factor_iter( + &self, + ) -> IterEither<<&L as IntoIterator>::IntoIter, <&R as IntoIterator>::IntoIter> + where + for<'a> &'a L: IntoIterator, + for<'a> &'a R: IntoIterator, + { + IterEither::new(map_either!(self, inner => inner.into_iter())) + } + + /// Mutably borrows an `Either` of `Iterator`s to be an `Iterator` of `Either`s + /// + /// Unlike [`iter_mut`][Either::iter_mut], this does not require the + /// `Left` and `Right` iterators to have the same item type. + /// + /// ``` + /// use either::*; + /// let mut left: Either<_, Vec> = Left(["hello"]); + /// left.factor_iter_mut().for_each(|x| *x.unwrap_left() = "goodbye"); + /// assert_eq!(left, Left(["goodbye"])); + + /// let mut right: Either<[&str; 2], _> = Right(vec![0, 1, 2]); + /// right.factor_iter_mut().for_each(|x| if let Right(r) = x { *r = -*r; }); + /// assert_eq!(right, Right(vec![0, -1, -2])); + /// + /// ``` + pub fn factor_iter_mut( + &mut self, + ) -> IterEither<<&mut L as IntoIterator>::IntoIter, <&mut R as IntoIterator>::IntoIter> + where + for<'a> &'a mut L: IntoIterator, + for<'a> &'a mut R: IntoIterator, + { + IterEither::new(map_either!(self, inner => inner.into_iter())) } /// Return left value or given value @@ -972,158 +1111,6 @@ impl Into> for Either { } } -impl Extend for Either -where - L: Extend, - R: Extend, -{ - fn extend(&mut self, iter: T) - where - T: IntoIterator, - { - for_both!(*self, ref mut inner => inner.extend(iter)) - } -} - -/// `Either` is an iterator if both `L` and `R` are iterators. -impl Iterator for Either -where - L: Iterator, - R: Iterator, -{ - type Item = L::Item; - - fn next(&mut self) -> Option { - for_both!(*self, ref mut inner => inner.next()) - } - - fn size_hint(&self) -> (usize, Option) { - for_both!(*self, ref inner => inner.size_hint()) - } - - fn fold(self, init: Acc, f: G) -> Acc - where - G: FnMut(Acc, Self::Item) -> Acc, - { - for_both!(self, inner => inner.fold(init, f)) - } - - fn for_each(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 { - for_both!(self, inner => inner.last()) - } - - fn nth(&mut self, n: usize) -> Option { - for_both!(*self, ref mut inner => inner.nth(n)) - } - - fn collect(self) -> B - where - B: iter::FromIterator, - { - for_both!(self, inner => inner.collect()) - } - - fn partition(self, f: F) -> (B, B) - where - B: Default + Extend, - F: FnMut(&Self::Item) -> bool, - { - for_both!(self, inner => inner.partition(f)) - } - - fn all(&mut self, f: F) -> bool - where - F: FnMut(Self::Item) -> bool, - { - for_both!(*self, ref mut inner => inner.all(f)) - } - - fn any(&mut self, f: F) -> bool - where - F: FnMut(Self::Item) -> bool, - { - for_both!(*self, ref mut inner => inner.any(f)) - } - - fn find

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

(&mut self, predicate: P) -> Option - where - P: FnMut(Self::Item) -> bool, - { - for_both!(*self, ref mut inner => inner.position(predicate)) - } -} - -impl DoubleEndedIterator for Either -where - L: DoubleEndedIterator, - R: DoubleEndedIterator, -{ - fn next_back(&mut self) -> Option { - 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 { - // for_both!(*self, ref mut inner => inner.nth_back(n)) - // } - - fn rfold(self, init: Acc, f: G) -> Acc - where - G: FnMut(Acc, Self::Item) -> Acc, - { - for_both!(self, inner => inner.rfold(init, f)) - } - - fn rfind

(&mut self, predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - for_both!(*self, ref mut inner => inner.rfind(predicate)) - } -} - -impl ExactSizeIterator for Either -where - L: ExactSizeIterator, - R: ExactSizeIterator, -{ - fn len(&self) -> usize { - for_both!(*self, ref inner => inner.len()) - } -} - -impl iter::FusedIterator for Either -where - L: iter::FusedIterator, - R: iter::FusedIterator, -{ -} - /// `Either` is a future if both `L` and `R` are futures. impl Future for Either where