Skip to content

Commit b785e6d

Browse files
hovinenbcopybara-github
authored andcommitted
Support counting the actual size correctly in ZippedIterator.
This eliminates the need to use Iterator::size_hint to get an estimate of the actual value's size in ElementsAreMatcher, instead consuming the actual iterator to get the real size when reporting a mismatch. PiperOrigin-RevId: 515587892
1 parent 1a6bcf1 commit b785e6d

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

googletest/src/matchers/elements_are_matcher.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,6 @@ pub mod internal {
113113

114114
fn explain_match(&self, actual: &ContainerT) -> MatchExplanation {
115115
let actual_iterator = actual.into_iter();
116-
// TODO(b/271570144): This is a lower bound and not an actual value, so fix it
117-
// to use the real number of elements in actual.
118-
let actual_size = actual_iterator.size_hint().0;
119116
let mut zipped_iterator = zip(actual_iterator, self.elements.iter());
120117
let mut mismatches = Vec::new();
121118
for (idx, (a, e)) in zipped_iterator.by_ref().enumerate() {
@@ -127,7 +124,10 @@ pub mod internal {
127124
if !zipped_iterator.has_size_mismatch() {
128125
MatchExplanation::create("whose elements all match".to_string())
129126
} else {
130-
MatchExplanation::create(format!("whose size is {}", actual_size))
127+
MatchExplanation::create(format!(
128+
"whose size is {}",
129+
zipped_iterator.left_size()
130+
))
131131
}
132132
} else if mismatches.len() == 1 {
133133
let mismatches = mismatches.into_iter().collect::<Description>();

googletest/src/matchers/zipped_iterator.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
///
77
/// [`Iterator::zip`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.zip
88
pub(crate) fn zip<I1, I2>(left: I1, right: I2) -> ZippedIterator<I1, I2> {
9-
ZippedIterator { left, right, has_size_mismatch: false }
9+
ZippedIterator { left, right, has_size_mismatch: false, consumed_elements: 0 }
1010
}
1111

1212
/// An iterator over pairs of the elements of two constituent iterators, which
@@ -21,9 +21,10 @@ pub(crate) struct ZippedIterator<I1, I2> {
2121
left: I1,
2222
right: I2,
2323
has_size_mismatch: bool,
24+
consumed_elements: usize,
2425
}
2526

26-
impl<I1, I2> ZippedIterator<I1, I2> {
27+
impl<I1: Iterator, I2> ZippedIterator<I1, I2> {
2728
/// Returns whether a mismatch in the two sizes of the two iterators was
2829
/// detected during iteration.
2930
///
@@ -35,19 +36,36 @@ impl<I1, I2> ZippedIterator<I1, I2> {
3536
pub(crate) fn has_size_mismatch(&self) -> bool {
3637
self.has_size_mismatch
3738
}
39+
40+
/// Returns the number of elements in the left iterator.
41+
///
42+
/// This iterates through the remainder of the left iterator if necessary in
43+
/// order to get the true number of elements. It therefore consumes `self`.
44+
pub(crate) fn left_size(mut self) -> usize {
45+
self.consumed_elements + self.left.by_ref().count()
46+
}
3847
}
3948

4049
impl<I1: Iterator, I2: Iterator> Iterator for ZippedIterator<I1, I2> {
4150
type Item = (I1::Item, I2::Item);
4251

4352
fn next(&mut self) -> Option<(I1::Item, I2::Item)> {
4453
match (self.left.next(), self.right.next()) {
45-
(Some(v1), Some(v2)) => Some((v1, v2)),
46-
(None, None) => None,
47-
_ => {
54+
(Some(v1), Some(v2)) => {
55+
self.consumed_elements += 1;
56+
Some((v1, v2))
57+
}
58+
(Some(_), None) => {
59+
// Consumed elements counts only elements from self.left
60+
self.consumed_elements += 1;
4861
self.has_size_mismatch = true;
4962
None
5063
}
64+
(None, Some(_)) => {
65+
self.has_size_mismatch = true;
66+
None
67+
}
68+
(None, None) => None,
5169
}
5270
}
5371
}

0 commit comments

Comments
 (0)