lender/adapters/
zip.rs

1use crate::{
2    DoubleEndedLender, ExactSizeLender, FallibleLend, FallibleLender, FallibleLending, FusedFallibleLender, FusedLender,
3    IntoLender, Lend, Lender, Lending,
4};
5
6pub fn zip<A, B>(a: A, b: B) -> Zip<A::Lender, B::Lender>
7where
8    A: IntoLender,
9    B: IntoLender,
10{
11    Zip::new(a.into_lender(), b.into_lender())
12}
13
14#[derive(Clone)]
15#[must_use = "lenders are lazy and do nothing unless consumed"]
16pub struct Zip<A, B> {
17    a: A,
18    b: B,
19}
20impl<A, B> Zip<A, B> {
21    pub(crate) fn new(a: A, b: B) -> Self {
22        Self { a, b }
23    }
24    pub fn into_inner(self) -> (A, B) {
25        (self.a, self.b)
26    }
27}
28impl<'lend, A, B> Lending<'lend> for Zip<A, B>
29where
30    A: Lender,
31    B: Lender,
32{
33    type Lend = (Lend<'lend, A>, Lend<'lend, B>);
34}
35impl<A, B> Lender for Zip<A, B>
36where
37    A: Lender,
38    B: Lender,
39{
40    #[inline]
41    fn next(&mut self) -> Option<Lend<'_, Self>> {
42        Some((self.a.next()?, self.b.next()?))
43    }
44    #[inline]
45    fn size_hint(&self) -> (usize, Option<usize>) {
46        let (a_lower, a_upper) = self.a.size_hint();
47        let (b_lower, b_upper) = self.b.size_hint();
48
49        let lower = core::cmp::min(a_lower, b_lower);
50
51        let upper = match (a_upper, b_upper) {
52            (Some(x), Some(y)) => Some(core::cmp::min(x, y)),
53            (Some(x), None) => Some(x),
54            (None, Some(y)) => Some(y),
55            (None, None) => None,
56        };
57
58        (lower, upper)
59    }
60}
61impl<A, B> DoubleEndedLender for Zip<A, B>
62where
63    A: DoubleEndedLender + ExactSizeIterator,
64    B: DoubleEndedLender + ExactSizeIterator,
65{
66    #[inline]
67    fn next_back(&mut self) -> Option<Lend<'_, Self>> {
68        let a_sz = self.a.len();
69        let b_sz = self.b.len();
70        if a_sz != b_sz {
71            // Adjust a, b to equal length
72            if a_sz > b_sz {
73                for _ in 0..a_sz - b_sz {
74                    self.a.next_back();
75                }
76            } else {
77                for _ in 0..b_sz - a_sz {
78                    self.b.next_back();
79                }
80            }
81        }
82        match (self.a.next_back(), self.b.next_back()) {
83            (Some(x), Some(y)) => Some((x, y)),
84            (None, None) => None,
85            _ => unreachable!(),
86        }
87    }
88}
89impl<A, B> ExactSizeLender for Zip<A, B>
90where
91    A: ExactSizeLender,
92    B: ExactSizeLender,
93{
94}
95impl<A, B> FusedLender for Zip<A, B>
96where
97    A: FusedLender,
98    B: FusedLender,
99{
100}
101
102impl<'lend, A, B> FallibleLending<'lend> for Zip<A, B>
103where
104    A: FallibleLender,
105    B: FallibleLender<Error = A::Error>,
106{
107    type Lend = (FallibleLend<'lend, A>, FallibleLend<'lend, B>);
108}
109impl<A, B> FallibleLender for Zip<A, B>
110where
111    A: FallibleLender,
112    B: FallibleLender<Error = A::Error>,
113{
114    type Error = A::Error;
115
116    #[inline]
117    fn next(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
118        let Some(value_a) = self.a.next()? else { return Ok(None) };
119        let Some(value_b) = self.b.next()? else { return Ok(None) };
120        Ok(Some((value_a, value_b)))
121    }
122    #[inline]
123    fn size_hint(&self) -> (usize, Option<usize>) {
124        let (a_lower, a_upper) = self.a.size_hint();
125        let (b_lower, b_upper) = self.b.size_hint();
126
127        let lower = core::cmp::min(a_lower, b_lower);
128
129        let upper = match (a_upper, b_upper) {
130            (Some(x), Some(y)) => Some(core::cmp::min(x, y)),
131            (Some(x), None) => Some(x),
132            (None, Some(y)) => Some(y),
133            (None, None) => None,
134        };
135
136        (lower, upper)
137    }
138}
139impl<A, B> FusedFallibleLender for Zip<A, B>
140where
141    A: FusedFallibleLender,
142    B: FusedFallibleLender<Error = A::Error>,
143{
144}