fast_pull/base/
progress.rs1use core::ops::Range;
4
5pub type ProgressEntry = Range<u64>;
9
10pub trait Total {
12 fn total(&self) -> u64;
14}
15
16impl Total for ProgressEntry {
17 #[allow(clippy::inline_always)]
18 #[inline(always)]
19 fn total(&self) -> u64 {
20 self.end.saturating_sub(self.start)
21 }
22}
23
24impl Total for [ProgressEntry] {
34 fn total(&self) -> u64 {
35 self.iter()
36 .fold(0, |total, entry| total.saturating_add(entry.total()))
37 }
38}
39
40impl Total for Vec<ProgressEntry> {
41 fn total(&self) -> u64 {
42 self.as_slice().total()
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn progress_entry_total() {
52 assert_eq!((0..0).total(), 0);
53 assert_eq!((5..10).total(), 5);
54 assert_eq!((3..3).total(), 0);
55 let reversed = core::ops::Range { start: 10, end: 5 };
57 assert_eq!(reversed.total(), 0);
58 }
59
60 #[test]
61 fn vec_progress_total() {
62 #![allow(clippy::single_range_in_vec_init)]
63 let v: Vec<ProgressEntry> = vec![1..5, 8..10, 12..15];
64 assert_eq!(v.total(), 9);
65 let empty: Vec<ProgressEntry> = vec![];
66 assert_eq!(empty.total(), 0);
67 }
68
69 #[test]
70 fn slice_progress_total_matches_vec() {
71 #![allow(clippy::single_range_in_vec_init)]
72 let v: Vec<ProgressEntry> = vec![1..5, 8..10, 12..15];
73 assert_eq!(v.as_slice().total(), v.total());
74 let empty: &[ProgressEntry] = &[];
75 assert_eq!(empty.total(), 0);
76 }
77
78 #[test]
79 fn progress_entry_total_reversed_ranges_are_safe() {
80 assert_eq!((core::ops::Range { start: 10, end: 5 }).total(), 0);
82 assert_eq!(
83 (core::ops::Range {
84 start: u64::MAX,
85 end: 0
86 })
87 .total(),
88 0
89 );
90 assert_eq!(
91 (core::ops::Range {
92 start: 100,
93 end: 99
94 })
95 .total(),
96 0
97 );
98 assert_eq!((core::ops::Range { start: 1, end: 0 }).total(), 0);
99 }
100
101 #[test]
102 fn progress_entry_total_extreme_and_degenerate() {
103 assert_eq!((0..u64::MAX).total(), u64::MAX);
105 assert_eq!((u64::MAX..u64::MAX).total(), 0);
106 assert_eq!((42..42).total(), 0);
107 assert_eq!((0..0).total(), 0);
108 }
109
110 #[test]
111 fn vec_progress_total_counts_overlap_twice() {
112 #![allow(clippy::single_range_in_vec_init)]
113 let v: Vec<ProgressEntry> = vec![0..5, 3..10];
116 assert_eq!(v.total(), 12);
118 }
119
120 #[test]
121 fn vec_progress_total_overflow_saturates() {
122 let v: Vec<ProgressEntry> = vec![0..u64::MAX, 0..1];
123 assert_eq!(v.total(), u64::MAX);
124 }
125}