use crate::{DoubleEndedLender, ExactSizeLender, FusedLender, IntoLender, Lend, Lender, Lending};
#[inline]
pub fn zip<A, B>(a: A, b: B) -> Zip<A::Lender, B::Lender>
where
A: IntoLender,
B: IntoLender,
{
Zip::new(a.into_lender(), b.into_lender())
}
#[derive(Clone, Debug)]
#[must_use = "lenders are lazy and do nothing unless consumed"]
pub struct Zip<A, B> {
pub(crate) a: A,
pub(crate) b: B,
}
impl<A, B> Zip<A, B> {
#[inline(always)]
pub fn into_inner(self) -> (A, B) {
(self.a, self.b)
}
}
impl<A: Lender, B: Lender> Zip<A, B> {
#[inline(always)]
pub(crate) fn new(a: A, b: B) -> Self {
let _ = A::__check_covariance(crate::CovariantProof::new());
let _ = B::__check_covariance(crate::CovariantProof::new());
Self { a, b }
}
}
impl<'lend, A, B> Lending<'lend> for Zip<A, B>
where
A: Lender,
B: Lender,
{
type Lend = (Lend<'lend, A>, Lend<'lend, B>);
}
impl<A, B> Lender for Zip<A, B>
where
A: Lender,
B: Lender,
{
crate::unsafe_assume_covariance!();
#[inline]
fn next(&mut self) -> Option<Lend<'_, Self>> {
Some((self.a.next()?, self.b.next()?))
}
#[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 = core::cmp::min(a_lower, b_lower);
let upper = match (a_upper, b_upper) {
(Some(x), Some(y)) => Some(core::cmp::min(x, y)),
(Some(x), None) => Some(x),
(None, Some(y)) => Some(y),
(None, None) => None,
};
(lower, upper)
}
}
impl<A, B> DoubleEndedLender for Zip<A, B>
where
A: DoubleEndedLender + ExactSizeLender,
B: DoubleEndedLender + ExactSizeLender,
{
#[inline]
fn next_back(&mut self) -> Option<Lend<'_, Self>> {
let a_sz = self.a.len();
let b_sz = self.b.len();
if a_sz > b_sz {
self.a.advance_back_by(a_sz - b_sz).ok();
} else if b_sz > a_sz {
self.b.advance_back_by(b_sz - a_sz).ok();
}
match (self.a.next_back(), self.b.next_back()) {
(Some(x), Some(y)) => Some((x, y)),
(None, None) => None,
_ => unreachable!(),
}
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Lend<'_, Self>> {
let a_sz = self.a.len();
let b_sz = self.b.len();
if a_sz > b_sz {
self.a.advance_back_by(a_sz - b_sz).ok();
} else if b_sz > a_sz {
self.b.advance_back_by(b_sz - a_sz).ok();
}
match (self.a.nth_back(n), self.b.nth_back(n)) {
(Some(x), Some(y)) => Some((x, y)),
(None, None) => None,
_ => unreachable!(),
}
}
}
impl<A, B> ExactSizeLender for Zip<A, B>
where
A: ExactSizeLender,
B: ExactSizeLender,
{
}
impl<A, B> FusedLender for Zip<A, B>
where
A: FusedLender,
B: FusedLender,
{
}