rscompress_transformation/
runlength.rs

1//! Run-length Transformation
2//!
3//! Implementation of a run-length transformation as
4//! described [here](https://sites.google.com/site/datacompressionguide/rlt).
5use crate::{Transform, TransformError};
6use log::info;
7
8const RUN_BYTE_CODE: u8 = 0;
9
10/// Run-length struct to save current byte and metainformation about special cases
11#[derive(Debug)]
12pub struct RunLength {
13    current: Option<u8>,
14    reverse_started: bool,
15}
16
17impl RunLength {
18    pub fn new() -> Self {
19        RunLength {
20            current: None,
21            reverse_started: false,
22        }
23    }
24}
25
26impl Default for RunLength {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32/// Implementation of the Transform trait for Run-Length
33impl Transform for RunLength {
34    fn transform(&mut self, source: &[u8]) -> Result<Vec<u8>, TransformError> {
35        if source.is_empty() {
36            return Err(TransformError::EmptyBufferError);
37        }
38        let mut result: Vec<u8> = Vec::with_capacity(source.len());
39        for byte in source.iter() {
40            info!("Transform: {} | {:?}", byte, self);
41            if self.current.is_some() && self.current.unwrap() == *byte {
42                result.push(RUN_BYTE_CODE);
43            } else if self.current.is_some() && RUN_BYTE_CODE == *byte {
44                result.push(self.current.unwrap());
45                self.current = Some(*byte);
46            } else {
47                result.push(*byte);
48                self.current = Some(*byte);
49            }
50        }
51        self.reverse_started = false;
52        Ok(result)
53    }
54
55    fn reverse(&mut self, source: &[u8]) -> Result<Vec<u8>, TransformError> {
56        if source.is_empty() {
57            return Err(TransformError::EmptyBufferError);
58        }
59        let mut result: Vec<u8> = Vec::with_capacity(source.len());
60        for byte in source.iter() {
61            info!("Reverse: {} | {:?}", byte, self);
62            if self.current.is_some() && *byte == RUN_BYTE_CODE && self.reverse_started {
63                result.push(self.current.unwrap());
64                self.reverse_started = true;
65            } else if self.current.is_some()
66                && *byte == self.current.unwrap()
67                && self.reverse_started
68            {
69                result.push(RUN_BYTE_CODE);
70                self.current = Some(RUN_BYTE_CODE);
71                self.reverse_started = true;
72            } else {
73                result.push(*byte);
74                self.current = Some(*byte);
75                self.reverse_started = true;
76            }
77        }
78        Ok(result)
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use crate::tests::{random_roundtrip, reverse, roundtrip, transform};
86
87    #[test]
88    fn test_easy_transforms() {
89        transform::<RunLength>(
90            &[8, 2, 2, 2, 24, 32, 32, 1, 24],
91            &[
92                8,
93                2,
94                RUN_BYTE_CODE,
95                RUN_BYTE_CODE,
96                24,
97                32,
98                RUN_BYTE_CODE,
99                1,
100                24,
101            ],
102        );
103    }
104    #[test]
105    fn test_easy_reverses() {
106        reverse::<RunLength>(
107            &[
108                8,
109                2,
110                RUN_BYTE_CODE,
111                RUN_BYTE_CODE,
112                24,
113                32,
114                RUN_BYTE_CODE,
115                1,
116                24,
117            ],
118            &[8, 2, 2, 2, 24, 32, 32, 1, 24],
119        );
120        reverse::<RunLength>(
121            &[8, RUN_BYTE_CODE, RUN_BYTE_CODE, 8],
122            &[8, 8, 8, RUN_BYTE_CODE],
123        );
124    }
125
126    #[test]
127    fn test_roundtrip() {
128        roundtrip::<RunLength>(&[8, 2, 2, 2, 24, 32, 32, 1, 24]);
129        roundtrip::<RunLength>(&[8, 8, 8, 8, 2]);
130        roundtrip::<RunLength>(&[8, 8, 1, 2, 2]);
131        roundtrip::<RunLength>(&[8, 8, 8, 8]);
132        roundtrip::<RunLength>(&[RUN_BYTE_CODE, 8, 8, 8]);
133        roundtrip::<RunLength>(&[8, 1, 5, 8]);
134    }
135
136    #[test]
137    fn test_random_roundtrip() {
138        random_roundtrip::<RunLength>(100, 10_000);
139        random_roundtrip::<RunLength>(100, 10_000);
140        random_roundtrip::<RunLength>(100, 10_000);
141        random_roundtrip::<RunLength>(100, 10_000);
142        random_roundtrip::<RunLength>(100, 10_000);
143    }
144}