1use crate::ProgressEntry;
2
3pub struct InvertIter<'a, I: Iterator<Item = &'a ProgressEntry>> {
4 iter: I,
5 prev_end: u64,
6 total_size: u64,
7 window: u64,
8}
9
10impl<'a, I> Iterator for InvertIter<'a, I>
11where
12 I: Iterator<Item = &'a ProgressEntry>,
13{
14 type Item = ProgressEntry;
15 fn next(&mut self) -> Option<Self::Item> {
16 let mut gap_start = self.prev_end;
17 for range in self.iter.by_ref() {
18 if range.start == gap_start {
19 gap_start = range.end;
20 continue;
21 }
22 let len = range.end - range.start;
23 if len >= self.window {
24 self.prev_end = range.end;
25 return Some(gap_start..range.start);
26 }
27 }
28 if gap_start < self.total_size {
29 self.prev_end = self.total_size;
30 Some(gap_start..self.total_size)
31 } else {
32 None
33 }
34 }
35}
36
37pub fn invert<'a, I>(progress: I, total_size: u64, window: u64) -> InvertIter<'a, I>
39where
40 I: Iterator<Item = &'a ProgressEntry>,
41{
42 InvertIter {
43 iter: progress,
44 prev_end: 0,
45 total_size,
46 window,
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 #![allow(clippy::single_range_in_vec_init)]
53 extern crate alloc;
54 use super::*;
55
56 fn invert_vec(
57 progress: &[ProgressEntry],
58 total_size: u64,
59 window: u64,
60 ) -> alloc::vec::Vec<ProgressEntry> {
61 invert(progress.iter(), total_size, window).collect()
62 }
63
64 #[test]
65 fn test_windowed_invert() {
66 assert_eq!(invert_vec(&[10..20], 30, 1), [0..10, 20..30]);
67 assert_eq!(invert_vec(&[10..12], 30, 5), [0..30]);
68 assert_eq!(invert_vec(&[10..20, 25..27], 30, 5), [0..10, 20..30]);
69 assert_eq!(invert_vec(&[10..14, 25..27, 30..32], 50, 5), [0..50]);
70 assert_eq!(invert_vec(&[10..14, 25..49], 50, 5), [0..25, 49..50]);
71 assert_eq!(invert_vec(&[2..4, 6..8, 10..12], 15, 5), [0..15]);
72 assert_eq!(invert_vec(&[0..2, 10..20], 30, 5), [2..10, 20..30]);
73 }
74}