zip_long 0.1.1

iterator adaptors for zipping together two or more iterators
Documentation
#[cfg(test)]
mod tests;
use std::iter::FusedIterator;
/// Zip together two iterators, creating a single iterator that yields the item(s) in parallel until the longer iterator is exhausted.
/// Unlike the zip iterator adaptor in `::std::iter`, these adaptors yield elements until the LONGER iterator is exhausted.
/// ```
/// use zip::Zip;
/// ```
pub trait Zip: IntoIterator + Sized {
    /// zip together two iterators. when the shorter iterator runs out of items, replace them with fill until the longer iterator is exhausted.
    /// ```
    /// # use zip::Zip;
    /// let mut i: u8 = 0;
    /// let filler = || {
    ///    let c = (b'a' + i) as char;
    ///     i += 1;
    ///     c
    ///  };
    /// let want = vec![('A', 'a'), ('B', 'b'), ('C', 'c'), ('D', 'd')];
    /// let got: Vec<(char, char)> = vec!['A', 'B', 'C', 'D'].zip_fill(Vec::new(), filler).collect();
    /// assert_eq!(want, got);
    /// ```
    fn zip_fill<R, F>(self, r: R, fill: F) -> Filler<Self::IntoIter, R::IntoIter, F>
    where
        R: IntoIterator<Item = Self::Item>,
        F: FnMut() -> Self::Item,
    {
        Filler {
            q: self.into_iter(),
            r: r.into_iter(),
            fill,
        }
    }
    /// zip together two iterators. when the shorter iterator runs out of items, replace them with T::default until the longer iterator is exhausted.
    ///
    /// ```
    /// # use zip::Zip;
    /// let want = vec![(1, 2), (3, 4), (5, 6), (0, 8)];
    /// let got: Vec<(usize, usize)> = vec![1, 3, 5].zip_fill_default(vec![2, 4, 6, 8]).collect();
    /// assert_eq!(want, got);
    /// ```
    fn zip_fill_default<R>(self, r: R) -> Filler<Self::IntoIter, R::IntoIter, fn() -> Self::Item>
    where
        R: IntoIterator<Item = Self::Item>,
        Self::Item: Default,
    {
        Filler {
            q: self.into_iter(),
            r: r.into_iter(),
            fill: Self::Item::default,
        }
    }
    /// zip together two iterators. when the shorter iterator runs out of items, replace them with clones of `item` until the longer iterator is exhausted.
    /// ```
    /// # use zip::Zip;
    /// let q = vec![0_usize; 4];
    /// let r = vec![1_usize; 7];
    /// let want = vec![(0_usize, 1_usize); 7];
    /// let got: Vec<(usize, usize)> = q.into_iter().zip_fill_with(r, 0).collect();
    /// assert_eq!(want, got);
    /// ```
    fn zip_fill_with<R>(self, r: R, item: Self::Item) -> FillerWith<Self::IntoIter, R::IntoIter>
    where
        R: IntoIterator<Item = Self::Item>,
        Self::Item: Clone,
    {
        FillerWith {
            q: self.into_iter(),
            r: r.into_iter(),
            item,
        }
    }
}

impl<I: IntoIterator> Zip for I {}

#[derive(Debug)]
/// Filler zips together two iterators using the provided closure to fill in for the shorter iterator once it is exhausted.
pub struct Filler<Q, R, F>
where
    Q: Iterator,
    R: Iterator<Item = Q::Item>,
    F: FnMut() -> Q::Item,
{
    q: Q,
    r: R,
    fill: F,
}

#[derive(Debug)]
/// FillerWith zips together two iterators using clones of the provided item to fill in for the shorter iterator once is is exhausted.
pub struct FillerWith<Q: Iterator, R: Iterator<Item = Q::Item>> {
    q: Q,
    r: R,
    item: Q::Item,
}

impl<Q, R> Iterator for FillerWith<Q, R>
where
    Q: Iterator,
    R: Iterator<Item = Q::Item>,
    Q::Item: Clone,
{
    type Item = (Q::Item, Q::Item);
    fn next(&mut self) -> Option<Self::Item> {
        match (self.q.next(), self.r.next()) {
            (None, None) => None,
            (Some(q), None) => Some((q, self.item.clone())),
            (None, Some(r)) => Some((self.item.clone(), r)),
            (Some(q), Some(r)) => Some((q, r)),
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint(self.q.size_hint(), self.r.size_hint())
    }
}

impl<Q, R, F> Iterator for Filler<Q, R, F>
where
    Q: Iterator,
    R: Iterator<Item = Q::Item>,
    F: FnMut() -> Q::Item,
{
    type Item = (Q::Item, Q::Item);
    fn next(&mut self) -> Option<Self::Item> {
        match (self.q.next(), self.r.next()) {
            (None, None) => None,
            (Some(q), None) => Some((q, (self.fill)())),
            (None, Some(r)) => Some(((self.fill)(), r)),
            (Some(q), Some(r)) => Some((q, r)),
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint(self.q.size_hint(), self.r.size_hint())
    }
}

#[inline]
fn size_hint(
    (min_a, max_a): (usize, Option<usize>),
    (min_b, max_b): (usize, Option<usize>),
) -> (usize, Option<usize>) {
    let min = usize::max(min_a, min_b); // we have at least as many elements as the larger minimum
    let max = if let (Some(a), Some(b)) = (max_a, max_b) {
        Some(usize::max(a, b))
    } else {
        None
    };
    (min, max)
}

impl<Q, R> ExactSizeIterator for FillerWith<Q, R>
where
    Q: ExactSizeIterator,
    R: ExactSizeIterator<Item = Q::Item>,
    Q::Item: Clone,
{}
impl<Q, R> FusedIterator for FillerWith<Q, R>
where
    Q: FusedIterator,
    R: FusedIterator<Item = Q::Item>,
    Q::Item: Clone,
{}

impl<Q, R, F> ExactSizeIterator for Filler<Q, R, F>
where
    Q: ExactSizeIterator,
    R: ExactSizeIterator<Item = Q::Item>,
    F: FnMut() -> Q::Item,
{}

impl<Q, R, F> FusedIterator for Filler<Q, R, F>
where
    Q: FusedIterator,
    R: FusedIterator<Item = Q::Item>,
    F: FnMut() -> Q::Item,
{}