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