diff options
Diffstat (limited to 'src/rle.rs')
-rw-r--r-- | src/rle.rs | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/src/rle.rs b/src/rle.rs new file mode 100644 index 0000000..f6d1e05 --- /dev/null +++ b/src/rle.rs | |||
@@ -0,0 +1,89 @@ | |||
1 | pub trait RLE { | ||
2 | type Data; | ||
3 | fn compress(&self) -> Vec<Run<Self::Data>>; | ||
4 | fn decompress(runs: Vec<Run<Self::Data>>) -> Vec<Self::Data>; | ||
5 | } | ||
6 | |||
7 | pub type Run<T> = (T, usize); | ||
8 | |||
9 | impl<T> RLE for Vec<T> | ||
10 | where | ||
11 | T: Clone + PartialEq, | ||
12 | { | ||
13 | type Data = T; | ||
14 | fn compress(&self) -> Vec<Run<Self::Data>> { | ||
15 | let mut runs = vec![]; | ||
16 | if self.is_empty() { | ||
17 | return runs; | ||
18 | } | ||
19 | let mut idx = 0; | ||
20 | loop { | ||
21 | let first = &self[idx]; | ||
22 | let run_length = self[idx..].iter().take_while(|&item| item == first).count(); | ||
23 | |||
24 | runs.push((first.clone(), run_length)); | ||
25 | |||
26 | idx += run_length; | ||
27 | if idx > self.len() - 1 { | ||
28 | break; | ||
29 | } | ||
30 | } | ||
31 | runs | ||
32 | } | ||
33 | fn decompress(runs: Vec<Run<Self::Data>>) -> Vec<Self::Data> { | ||
34 | runs.into_iter() | ||
35 | .map(|(item, size)| vec![item; size]) | ||
36 | .flatten() | ||
37 | .collect() | ||
38 | } | ||
39 | } | ||
40 | |||
41 | #[cfg(test)] | ||
42 | mod tests { | ||
43 | use super::*; | ||
44 | #[test] | ||
45 | fn singleton() { | ||
46 | let data = "a".chars().collect::<Vec<_>>(); | ||
47 | assert_eq!(Vec::<char>::compress(&data), vec![('a', 1),]); | ||
48 | } | ||
49 | #[test] | ||
50 | fn identity() { | ||
51 | let data = "aabbccddaabbaa".chars().collect::<Vec<_>>(); | ||
52 | assert_eq!(Vec::<char>::decompress(data.compress()), data); | ||
53 | } | ||
54 | #[test] | ||
55 | fn repeated_singleton() { | ||
56 | let data = "aaaaaaaaaaaaa".chars().collect::<Vec<_>>(); | ||
57 | assert_eq!(Vec::<char>::compress(&data), vec![('a', 13),]); | ||
58 | } | ||
59 | #[test] | ||
60 | fn empty_runs() { | ||
61 | let data = "".chars().collect::<Vec<_>>(); | ||
62 | assert!(data.compress().is_empty()); | ||
63 | } | ||
64 | #[test] | ||
65 | fn empty_decompress() { | ||
66 | assert!(Vec::<char>::decompress(vec![]).is_empty()); | ||
67 | } | ||
68 | #[test] | ||
69 | fn check_runs1() { | ||
70 | let data = "aaaabbbbcccc".chars().collect::<Vec<_>>(); | ||
71 | assert_eq!(data.compress(), vec![('a', 4), ('b', 4), ('c', 4)]); | ||
72 | } | ||
73 | #[test] | ||
74 | fn check_runs2() { | ||
75 | let data = "aabbccddaabbaa".chars().collect::<Vec<_>>(); | ||
76 | assert_eq!( | ||
77 | data.compress(), | ||
78 | vec![ | ||
79 | ('a', 2), | ||
80 | ('b', 2), | ||
81 | ('c', 2), | ||
82 | ('d', 2), | ||
83 | ('a', 2), | ||
84 | ('b', 2), | ||
85 | ('a', 2) | ||
86 | ] | ||
87 | ); | ||
88 | } | ||
89 | } | ||