1//! Arithmetic on `Iterator.size_hint()` values.
2//!
3
4use std::cmp;
5use std::usize;
6
7/// `SizeHint` is the return type of `Iterator::size_hint()`.
8pub type SizeHint = (usize, Option<usize>);
9
10/// Add `SizeHint` correctly.
11#[inline]
12pub fn add(a: SizeHint, b: SizeHint) -> SizeHint {
13 let min: usize = a.0.saturating_add(b.0);
14 let max: Option = match (a.1, b.1) {
15 (Some(x: usize), Some(y: usize)) => x.checked_add(y),
16 _ => None,
17 };
18
19 (min, max)
20}
21
22/// Add `x` correctly to a `SizeHint`.
23#[inline]
24pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint {
25 let (mut low: usize, mut hi: Option) = sh;
26 low = low.saturating_add(x);
27 hi = hi.and_then(|elt: usize| elt.checked_add(x));
28 (low, hi)
29}
30
31/// Subtract `x` correctly from a `SizeHint`.
32#[inline]
33pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint {
34 let (mut low: usize, mut hi: Option) = sh;
35 low = low.saturating_sub(x);
36 hi = hi.map(|elt: usize| elt.saturating_sub(x));
37 (low, hi)
38}
39
40/// Multiply `SizeHint` correctly
41#[inline]
42pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint {
43 let low: usize = a.0.saturating_mul(b.0);
44 let hi: Option = match (a.1, b.1) {
45 (Some(x: usize), Some(y: usize)) => x.checked_mul(y),
46 (Some(0), None) | (None, Some(0)) => Some(0),
47 _ => None,
48 };
49 (low, hi)
50}
51
52/// Multiply `x` correctly with a `SizeHint`.
53#[inline]
54pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint {
55 let (mut low: usize, mut hi: Option) = sh;
56 low = low.saturating_mul(x);
57 hi = hi.and_then(|elt: usize| elt.checked_mul(x));
58 (low, hi)
59}
60
61/// Return the maximum
62#[inline]
63pub fn max(a: SizeHint, b: SizeHint) -> SizeHint {
64 let (a_lower: usize, a_upper: Option) = a;
65 let (b_lower: usize, b_upper: Option) = b;
66
67 let lower: usize = cmp::max(v1:a_lower, v2:b_lower);
68
69 let upper: Option = match (a_upper, b_upper) {
70 (Some(x: usize), Some(y: usize)) => Some(cmp::max(v1:x, v2:y)),
71 _ => None,
72 };
73
74 (lower, upper)
75}
76
77/// Return the minimum
78#[inline]
79pub fn min(a: SizeHint, b: SizeHint) -> SizeHint {
80 let (a_lower: usize, a_upper: Option) = a;
81 let (b_lower: usize, b_upper: Option) = b;
82 let lower: usize = cmp::min(v1:a_lower, v2:b_lower);
83 let upper: Option = match (a_upper, b_upper) {
84 (Some(u1: usize), Some(u2: usize)) => Some(cmp::min(v1:u1, v2:u2)),
85 _ => a_upper.or(optb:b_upper),
86 };
87 (lower, upper)
88}
89
90#[test]
91fn mul_size_hints() {
92 assert_eq!(mul((3, Some(4)), (3, Some(4))), (9, Some(16)));
93 assert_eq!(mul((3, Some(4)), (usize::MAX, None)), (usize::MAX, None));
94 assert_eq!(mul((3, None), (0, Some(0))), (0, Some(0)));
95}
96