use std::cmp;
use std::iter::IntoIterator;
#[doc(hidden)]
#[derive(Clone, Debug)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct ZipOption {
a: A,
b: B,
// index and len are only used by the specialized version of zip
index: usize,
len: usize,
}
/// Zips to iterators together to the longest length
/// via Option<(Option, Option)>
pub trait ZipOpt {
/// Zip to iterators to longest length via Option<(Option, Option)> results.
/// # Example
/// ```
/// use array_tool::iter::ZipOpt;
///
/// let a = vec!["a","b","c", "d"];
/// let b = vec!["c","d"];
/// let mut x = a.iter().zip_option(b.iter());
///
/// assert_eq!(x.next(), Some((Some(&"a"), Some(&"c"))));
/// assert_eq!(x.next(), Some((Some(&"b"), Some(&"d"))));
/// assert_eq!(x.next(), Some((Some(&"c"), None)));
/// assert_eq!(x.next(), Some((Some(&"d"), None)));
/// assert_eq!(x.next(), None);
/// ```
///
/// # Output
/// ```text
/// vec![ "a", "b", "c", "d" ]
/// ```
fn zip_option(self, other: U) -> ZipOption
where Self: Sized, U: IntoIterator;
}
impl ZipOpt for I {
#[inline]
fn zip_option(self, other: U) -> ZipOption
where Self: Sized, U: IntoIterator {
ZipOption::new(self, other.into_iter())
}
}
impl Iterator for ZipOption where A: Iterator, B: Iterator {
type Item = (Option, Option);
#[inline]
fn next(&mut self) -> Option {
ZipImpl::next(self)
}
#[inline]
fn size_hint(&self) -> (usize, Option) {
ZipImpl::size_hint(self)
}
#[inline]
fn nth(&mut self, n: usize) -> Option {
ZipImpl::nth(self, n)
}
}
#[doc(hidden)]
impl DoubleEndedIterator for ZipOption where
A: DoubleEndedIterator + ExactSizeIterator,
B: DoubleEndedIterator + ExactSizeIterator,
{
#[inline]
fn next_back(&mut self) -> Option<(Option, Option)> {
ZipImpl::next_back(self)
}
}
#[doc(hidden)]
trait ZipImpl {
type Item;
fn new(a: A, b: B) -> Self;
fn next(&mut self) -> Option;
fn size_hint(&self) -> (usize, Option);
fn nth(&mut self, n: usize) -> Option;
fn super_nth(&mut self, mut n: usize) -> Option {
while let Some(x) = self.next() {
if n == 0 { return Some(x) }
n -= 1;
}
None
}
fn next_back(&mut self) -> Option
where A: DoubleEndedIterator + ExactSizeIterator,
B: DoubleEndedIterator + ExactSizeIterator;
}
#[doc(hidden)]
impl ZipImpl for ZipOption
where A: Iterator, B: Iterator {
type Item = (Option, Option);
fn new(a: A, b: B) -> Self {
ZipOption {
a,
b,
index: 0, // unused
len: 0, // unused
}
}
#[inline]
fn next(&mut self) -> Option<(Option, Option)> {
let first = self.a.next();
let second = self.b.next();
if first.is_some() || second.is_some() {
Some((first, second))
} else {
None
}
}
#[inline]
fn nth(&mut self, n: usize) -> Option {
self.super_nth(n)
}
#[inline]
fn next_back(&mut self) -> Option<(Option, Option)>
where A: DoubleEndedIterator + ExactSizeIterator,
B: DoubleEndedIterator + ExactSizeIterator {
let a_sz = self.a.len();
let b_sz = self.b.len();
if a_sz != b_sz {
// Adjust a, b to equal length
if a_sz > b_sz {
for _ in 0..a_sz - b_sz { self.a.next_back(); }
} else {
for _ in 0..b_sz - a_sz { self.b.next_back(); }
}
}
match (self.a.next_back(), self.b.next_back()) {
(None, None) => None,
(f,s) => Some((f, s)),
}
}
#[inline]
fn size_hint(&self) -> (usize, Option) {
let (a_lower, a_upper) = self.a.size_hint();
let (b_lower, b_upper) = self.b.size_hint();
let lower = cmp::min(a_lower, b_lower);
let upper = match (a_upper, b_upper) {
(Some(x), Some(y)) => Some(cmp::max(x,y)),
(Some(x), None) => Some(x),
(None, Some(y)) => Some(y),
(None, None) => None
};
(lower, upper)
}
}