citum_engine/values/
range.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum ConsecutiveSegment {
11 Single(u32),
13 Range {
15 start: u32,
17 end: u32,
19 },
20}
21
22#[must_use]
26pub fn consecutive_segments(values: &[u32]) -> Vec<ConsecutiveSegment> {
27 let mut iter = values.iter();
28 let Some(&first) = iter.next() else {
29 return Vec::new();
30 };
31
32 let mut segments = Vec::new();
33 let mut start = first;
34 let mut prev = first;
35
36 for &value in iter {
37 if value == prev {
38 continue;
39 }
40
41 if value == prev + 1 {
42 prev = value;
43 continue;
44 }
45
46 push_segment(&mut segments, start, prev);
47 start = value;
48 prev = value;
49 }
50
51 push_segment(&mut segments, start, prev);
52 segments
53}
54
55fn push_segment(segments: &mut Vec<ConsecutiveSegment>, start: u32, end: u32) {
56 if start == end {
57 segments.push(ConsecutiveSegment::Single(start));
58 } else {
59 segments.push(ConsecutiveSegment::Range { start, end });
60 }
61}
62
63#[cfg(test)]
64#[allow(
65 clippy::unwrap_used,
66 clippy::expect_used,
67 clippy::panic,
68 clippy::indexing_slicing,
69 clippy::todo,
70 clippy::unimplemented,
71 clippy::unreachable,
72 clippy::get_unwrap,
73 reason = "Panicking is acceptable and often desired in tests."
74)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_consecutive_segments() {
80 for (input, expected) in [
81 (&[][..], vec![]),
82 (&[1][..], vec![ConsecutiveSegment::Single(1)]),
83 (
84 &[1, 2, 3][..],
85 vec![ConsecutiveSegment::Range { start: 1, end: 3 }],
86 ),
87 (
88 &[1, 3, 5][..],
89 vec![
90 ConsecutiveSegment::Single(1),
91 ConsecutiveSegment::Single(3),
92 ConsecutiveSegment::Single(5),
93 ],
94 ),
95 (
96 &[1, 2, 4, 5, 6, 8][..],
97 vec![
98 ConsecutiveSegment::Range { start: 1, end: 2 },
99 ConsecutiveSegment::Range { start: 4, end: 6 },
100 ConsecutiveSegment::Single(8),
101 ],
102 ),
103 (
104 &[1, 1, 2, 2, 3][..],
105 vec![ConsecutiveSegment::Range { start: 1, end: 3 }],
106 ),
107 (
108 &[3, 2, 1][..],
109 vec![
110 ConsecutiveSegment::Single(3),
111 ConsecutiveSegment::Single(2),
112 ConsecutiveSegment::Single(1),
113 ],
114 ),
115 ] {
116 assert_eq!(consecutive_segments(input), expected);
117 }
118 }
119}