1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 /// Zips up two iterators into a single iterator of pairs.
16 ///
17 /// This is identical to [`Iterator::zip`] except that this version allows the
18 /// caller to determine whether the two iterators had mismatching sizes using
19 /// the method [`ZippedIterator::has_size_mismatch`].
20 ///
21 /// [`Iterator::zip`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.zip
zip<I1, I2>(left: I1, right: I2) -> ZippedIterator<I1, I2>22 pub(crate) fn zip<I1, I2>(left: I1, right: I2) -> ZippedIterator<I1, I2> {
23 ZippedIterator { left, right, has_size_mismatch: false, consumed_elements: 0 }
24 }
25
26 /// An iterator over pairs of the elements of two constituent iterators, which
27 /// keeps track of whether the two iterators have the same size.
28 ///
29 /// This is identical to [`Zip`] except that it allows the caller to determine
30 /// whether the two iterators had mismatching sizes using the method
31 /// [`ZippedIterator::has_size_mismatch`].
32 ///
33 /// [`Zip`]: https://doc.rust-lang.org/std/iter/struct.Zip.html
34 pub(crate) struct ZippedIterator<I1, I2> {
35 left: I1,
36 right: I2,
37 has_size_mismatch: bool,
38 consumed_elements: usize,
39 }
40
41 impl<I1: Iterator, I2> ZippedIterator<I1, I2> {
42 /// Returns whether a mismatch in the two sizes of the two iterators was
43 /// detected during iteration.
44 ///
45 /// This returns `true` if and only if, at some previous call to
46 /// [`Iterator::next`] on this instance, one of the constituent iterators
47 /// had a next element and the other did not.
48 ///
49 /// [`Iterator::next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
has_size_mismatch(&self) -> bool50 pub(crate) fn has_size_mismatch(&self) -> bool {
51 self.has_size_mismatch
52 }
53
54 /// Returns the number of elements in the left iterator.
55 ///
56 /// This iterates through the remainder of the left iterator if necessary in
57 /// order to get the true number of elements. It therefore consumes `self`.
left_size(mut self) -> usize58 pub(crate) fn left_size(mut self) -> usize {
59 self.consumed_elements + self.left.by_ref().count()
60 }
61 }
62
63 impl<I1: Iterator, I2: Iterator> Iterator for ZippedIterator<I1, I2> {
64 type Item = (I1::Item, I2::Item);
65
next(&mut self) -> Option<(I1::Item, I2::Item)>66 fn next(&mut self) -> Option<(I1::Item, I2::Item)> {
67 match (self.left.next(), self.right.next()) {
68 (Some(v1), Some(v2)) => {
69 self.consumed_elements += 1;
70 Some((v1, v2))
71 }
72 (Some(_), None) => {
73 // Consumed elements counts only elements from self.left
74 self.consumed_elements += 1;
75 self.has_size_mismatch = true;
76 None
77 }
78 (None, Some(_)) => {
79 self.has_size_mismatch = true;
80 None
81 }
82 (None, None) => None,
83 }
84 }
85 }
86