use std::cmp;
#[cfg(feature = "unstable")]
use std::iter::RandomAccessIterator;
use self::EitherOrBoth::{Right, Left, Both};
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct ZipLongest<T, U> {
a: T,
b: U
}
impl<T, U> ZipLongest<T, U>
{
pub fn new(a: T, b: U) -> ZipLongest<T, U>
{
ZipLongest{a: a, b: b}
}
}
impl<A, B, T, U> Iterator for ZipLongest<T, U> where
T: Iterator<Item=A>,
U: Iterator<Item=B>,
{
type Item = EitherOrBoth<A, B>;
#[inline]
fn next(&mut self) -> Option<EitherOrBoth<A, B>> {
match (self.a.next(), self.b.next()) {
(None, None) => None,
(Some(a), None) => Some(Left(a)),
(None, Some(b)) => Some(Right(b)),
(Some(a), Some(b)) => Some(Both(a, b)),
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (a_lower, a_upper) = self.a.size_hint();
let (b_lower, b_upper) = self.b.size_hint();
let lower = cmp::max(a_lower, b_lower);
let upper = match (a_upper, b_upper) {
(Some(x), Some(y)) => Some(cmp::max(x,y)),
_ => None
};
(lower, upper)
}
}
impl<A, B, T, U> DoubleEndedIterator for ZipLongest<T, U> where
T: DoubleEndedIterator<Item=A> + ExactSizeIterator,
U: DoubleEndedIterator<Item=B> + ExactSizeIterator,
{
#[inline]
fn next_back(&mut self) -> Option<EitherOrBoth<A, B>> {
use std::cmp::Ordering::{Equal, Greater, Less};
match self.a.len().cmp(&self.b.len()) {
Equal => match (self.a.next_back(), self.b.next_back()) {
(None, None) => None,
(Some(a), Some(b)) => Some(Both(a, b)),
(Some(a), None) => Some(Left(a)),
(None, Some(b)) => Some(Right(b)),
},
Greater => self.a.next_back().map(Left),
Less => self.b.next_back().map(Right),
}
}
}
#[cfg(feature = "unstable")]
impl<A, B, T, U> RandomAccessIterator for ZipLongest<T, U> where
T: RandomAccessIterator<Item=A>,
U: RandomAccessIterator<Item=B>,
{
#[inline]
fn indexable(&self) -> usize {
cmp::max(self.a.indexable(), self.b.indexable())
}
#[inline]
fn idx(&mut self, index: usize) -> Option<EitherOrBoth<A, B>> {
match (self.a.idx(index), self.b.idx(index)) {
(None, None) => None,
(Some(a), None) => Some(Left(a)),
(None, Some(b)) => Some(Right(b)),
(Some(a), Some(b)) => Some(Both(a, b)),
}
}
}
impl<T, U> ExactSizeIterator for ZipLongest<T, U> where
T: ExactSizeIterator,
U: ExactSizeIterator,
{}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum EitherOrBoth<A, B> {
Both(A, B),
Left(A),
Right(B),
}