diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index b5c0d42b1..23a86990c 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -176,24 +176,22 @@ where }; let (curr_lower, curr_upper) = curr_hint; let (next_lower, next_upper) = next_hint; - let (combined_lower, combined_upper) = - size_hint::mul_scalar(size_hint::min(curr_hint, next_hint), 2); let lower = if curr_lower > next_lower { - combined_lower + 1 + next_lower.saturating_mul(2).saturating_add(1) } else { - combined_lower + curr_lower.saturating_mul(2) }; - let upper = { - let extra_elem = match (curr_upper, next_upper) { - (_, None) => false, - (None, Some(_)) => true, - (Some(curr_max), Some(next_max)) => curr_max > next_max, - }; - if extra_elem { - combined_upper.and_then(|x| x.checked_add(1)) - } else { - combined_upper + let upper = match (curr_upper, next_upper) { + (Some(curr_max), Some(next_max)) => { + if curr_max > next_max { + next_max.checked_mul(2).and_then(|x| x.checked_add(1)) + } else { + curr_max.checked_mul(2) + } } + (Some(curr_max), None) => curr_max.checked_mul(2), + (None, Some(next_max)) => next_max.checked_mul(2).and_then(|x| x.checked_add(1)), + (None, None) => None, }; (lower, upper) } diff --git a/src/size_hint.rs b/src/size_hint.rs index f46f8fb14..9951f1b94 100644 --- a/src/size_hint.rs +++ b/src/size_hint.rs @@ -47,15 +47,6 @@ pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint { (low, hi) } -/// Multiply `x` correctly with a `SizeHint`. -#[inline] -pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint { - let (mut low, mut hi) = sh; - low = low.saturating_mul(x); - hi = hi.and_then(|elt| elt.checked_mul(x)); - (low, hi) -} - /// Return the maximum #[inline] pub fn max(a: SizeHint, b: SizeHint) -> SizeHint { diff --git a/tests/test_std.rs b/tests/test_std.rs index 5f5cfd1eb..838ca9011 100644 --- a/tests/test_std.rs +++ b/tests/test_std.rs @@ -86,6 +86,16 @@ fn interleave_shortest() { assert_eq!(it.size_hint(), (6, Some(6))); } +#[test] +fn interleave_shortest_size_hint_does_not_overflow() { + // The combined lower bound can exceed `usize::MAX`, which used to overflow + // when computing `size_hint`. It should saturate instead of panicking. + let i = ::std::iter::repeat(0u8).take(usize::MAX); + let j = ::std::iter::repeat(0u8).take(usize::MAX - 1); + let it = i.interleave_shortest(j); + assert_eq!(it.size_hint(), (usize::MAX, None)); +} + #[test] fn duplicates_by() { let xs = ["aaa", "bbbbb", "aa", "ccc", "bbbb", "aaaaa", "cccc"];