oxirs_tdb/compression/
run_length.rs1use crate::compression::{
4 AdvancedCompressionType, CompressedData, CompressionAlgorithm, CompressionMetadata,
5 MAX_BLOCK_COUNT, MAX_COMPRESSION_INPUT_SIZE,
6};
7use anyhow::{anyhow, Result};
8use std::collections::HashMap;
9use std::time::Instant;
10
11pub struct RunLengthEncoder;
13
14impl RunLengthEncoder {
15 pub fn encode(data: &[u8]) -> Result<Vec<u8>> {
17 if data.is_empty() {
19 return Ok(Vec::new());
20 }
21
22 if data.len() > MAX_COMPRESSION_INPUT_SIZE {
23 return Err(anyhow!(
24 "Input data too large for compression: {} bytes (max: {})",
25 data.len(),
26 MAX_COMPRESSION_INPUT_SIZE
27 ));
28 }
29
30 let mut encoded = Vec::new();
31 let mut current_byte = data[0];
32 let mut count = 1u32;
33
34 for &byte in &data[1..] {
35 if byte == current_byte && count < u32::MAX {
36 count += 1;
37 } else {
38 encoded.extend_from_slice(&count.to_le_bytes());
40 encoded.push(current_byte);
41 current_byte = byte;
42 count = 1;
43 }
44 }
45
46 encoded.extend_from_slice(&count.to_le_bytes());
48 encoded.push(current_byte);
49
50 Ok(encoded)
51 }
52
53 pub fn decode(encoded: &[u8]) -> Result<Vec<u8>> {
55 if encoded.is_empty() {
57 return Ok(Vec::new());
58 }
59
60 if encoded.len() % 5 != 0 {
61 return Err(anyhow!(
62 "Invalid run-length encoded data length: {} bytes",
63 encoded.len()
64 ));
65 }
66
67 if encoded.len() > MAX_COMPRESSION_INPUT_SIZE {
68 return Err(anyhow!(
69 "Encoded data too large for decompression: {} bytes (max: {})",
70 encoded.len(),
71 MAX_COMPRESSION_INPUT_SIZE
72 ));
73 }
74
75 let run_count = encoded.len() / 5;
76 if run_count > MAX_BLOCK_COUNT {
77 return Err(anyhow!(
78 "Too many runs in encoded data: {} (max: {})",
79 run_count,
80 MAX_BLOCK_COUNT
81 ));
82 }
83
84 let mut decoded = Vec::new();
85 let mut total_output_size = 0u64;
86
87 for chunk in encoded.chunks_exact(5) {
88 let count = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
89 let byte_value = chunk[4];
90
91 total_output_size += count as u64;
93 if total_output_size > MAX_COMPRESSION_INPUT_SIZE as u64 {
94 return Err(anyhow!(
95 "Decompressed data would exceed size limit: {} bytes (max: {})",
96 total_output_size,
97 MAX_COMPRESSION_INPUT_SIZE
98 ));
99 }
100
101 if count > 10_000_000 {
103 return Err(anyhow!(
104 "Suspicious run length detected: {} (possible decompression bomb)",
105 count
106 ));
107 }
108
109 for _ in 0..count {
110 decoded.push(byte_value);
111 }
112 }
113
114 Ok(decoded)
115 }
116
117 pub fn encode_u64(values: &[u64]) -> Vec<u8> {
121 if values.is_empty() {
122 return Vec::new();
123 }
124
125 let mut out = Vec::new();
126 let mut current = values[0];
127 let mut count = 1u32;
128
129 for &v in &values[1..] {
130 if v == current && count < u32::MAX {
131 count += 1;
132 } else {
133 out.extend_from_slice(¤t.to_le_bytes());
134 out.extend_from_slice(&count.to_le_bytes());
135 current = v;
136 count = 1;
137 }
138 }
139 out.extend_from_slice(¤t.to_le_bytes());
141 out.extend_from_slice(&count.to_le_bytes());
142
143 out
144 }
145
146 pub fn decode_u64(data: &[u8]) -> Result<Vec<u64>> {
148 if data.is_empty() {
149 return Ok(Vec::new());
150 }
151
152 if data.len() % 12 != 0 {
154 return Err(anyhow!(
155 "Invalid u64 RLE data: length {} is not a multiple of 12",
156 data.len()
157 ));
158 }
159
160 let run_count = data.len() / 12;
161 if run_count > MAX_BLOCK_COUNT {
162 return Err(anyhow!(
163 "Too many u64 RLE runs: {} (max: {})",
164 run_count,
165 MAX_BLOCK_COUNT
166 ));
167 }
168
169 let mut values = Vec::new();
170 let mut total: u64 = 0;
171
172 for chunk in data.chunks_exact(12) {
173 let value = u64::from_le_bytes(
174 chunk[..8]
175 .try_into()
176 .map_err(|_| anyhow!("u64 RLE slice error"))?,
177 );
178 let count = u32::from_le_bytes(
179 chunk[8..12]
180 .try_into()
181 .map_err(|_| anyhow!("u64 RLE count slice error"))?,
182 );
183
184 total += count as u64;
186 if total > 100_000_000 {
187 return Err(anyhow!(
188 "u64 RLE output exceeds 100M elements (possible decompression bomb)"
189 ));
190 }
191
192 for _ in 0..count {
193 values.push(value);
194 }
195 }
196
197 Ok(values)
198 }
199
200 pub fn estimate_compression_ratio(data: &[u8]) -> f64 {
202 if data.is_empty() {
203 return 1.0;
204 }
205
206 let mut runs = 0;
207 let mut current_byte = data[0];
208 for &byte in &data[1..] {
209 if byte != current_byte {
210 runs += 1;
211 current_byte = byte;
212 }
213 }
214 runs += 1; let compressed_size = runs * 5; compressed_size as f64 / data.len() as f64
218 }
219}
220
221impl CompressionAlgorithm for RunLengthEncoder {
222 fn compress(&self, data: &[u8]) -> Result<CompressedData> {
223 let start = Instant::now();
224 let compressed_bytes = Self::encode(data)?;
225 let compression_time = start.elapsed();
226
227 let mut metadata_map = HashMap::new();
228 metadata_map.insert("runs".to_string(), (compressed_bytes.len() / 5).to_string());
229
230 let metadata = CompressionMetadata {
231 algorithm: AdvancedCompressionType::RunLength,
232 original_size: data.len() as u64,
233 compressed_size: compressed_bytes.len() as u64,
234 compression_time_us: compression_time.as_micros() as u64,
235 metadata: metadata_map,
236 };
237
238 Ok(CompressedData {
239 data: compressed_bytes,
240 metadata,
241 })
242 }
243
244 fn decompress(&self, compressed: &CompressedData) -> Result<Vec<u8>> {
245 if compressed.metadata.algorithm != AdvancedCompressionType::RunLength {
246 return Err(anyhow!(
247 "Invalid compression algorithm: expected RunLength, got {}",
248 compressed.metadata.algorithm
249 ));
250 }
251
252 Self::decode(&compressed.data)
253 }
254
255 fn algorithm_type(&self) -> AdvancedCompressionType {
256 AdvancedCompressionType::RunLength
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 #[test]
265 fn test_run_length_encoding() {
266 let data = vec![1, 1, 1, 2, 2, 3, 3, 3, 3];
267 let encoded = RunLengthEncoder::encode(&data).unwrap();
268 let decoded = RunLengthEncoder::decode(&encoded).unwrap();
269 assert_eq!(data, decoded);
270 }
271
272 #[test]
273 fn test_empty_data() {
274 let data = vec![];
275 let encoded = RunLengthEncoder::encode(&data).unwrap();
276 assert!(encoded.is_empty());
277 }
278
279 #[test]
280 fn test_single_byte() {
281 let data = vec![42];
282 let encoded = RunLengthEncoder::encode(&data).unwrap();
283 let decoded = RunLengthEncoder::decode(&encoded).unwrap();
284 assert_eq!(data, decoded);
285 }
286
287 #[test]
288 fn test_compression_algorithm_trait() {
289 let encoder = RunLengthEncoder;
290 let data = vec![1, 1, 1, 2, 2, 3, 3, 3, 3];
291
292 let compressed = encoder.compress(&data).unwrap();
293 assert_eq!(
294 compressed.metadata.algorithm,
295 AdvancedCompressionType::RunLength
296 );
297 assert_eq!(compressed.metadata.original_size, data.len() as u64);
298
299 let decompressed = encoder.decompress(&compressed).unwrap();
300 assert_eq!(data, decompressed);
301 }
302
303 #[test]
304 fn test_estimate_compression_ratio() {
305 let highly_repetitive = vec![1; 1000];
306 let ratio = RunLengthEncoder::estimate_compression_ratio(&highly_repetitive);
307 assert!(ratio < 0.1); let random_data = (0..100).collect::<Vec<u8>>();
310 let ratio = RunLengthEncoder::estimate_compression_ratio(&random_data);
311 assert!(ratio > 1.0); }
313
314 #[test]
317 fn test_encode_u64_empty() {
318 let encoded = RunLengthEncoder::encode_u64(&[]);
319 assert!(encoded.is_empty());
320 }
321
322 #[test]
323 fn test_decode_u64_empty() {
324 let decoded = RunLengthEncoder::decode_u64(&[]).unwrap();
325 assert!(decoded.is_empty());
326 }
327
328 #[test]
329 fn test_encode_u64_single_value() {
330 let values = vec![42u64];
331 let encoded = RunLengthEncoder::encode_u64(&values);
332 let decoded = RunLengthEncoder::decode_u64(&encoded).unwrap();
333 assert_eq!(decoded, values);
334 }
335
336 #[test]
337 fn test_encode_u64_all_same() {
338 let values = vec![7u64; 100];
339 let encoded = RunLengthEncoder::encode_u64(&values);
340 assert_eq!(encoded.len(), 12);
342 let decoded = RunLengthEncoder::decode_u64(&encoded).unwrap();
343 assert_eq!(decoded, values);
344 }
345
346 #[test]
347 fn test_encode_u64_all_different() {
348 let values: Vec<u64> = (0..50).collect();
349 let encoded = RunLengthEncoder::encode_u64(&values);
350 assert_eq!(encoded.len(), 50 * 12);
352 let decoded = RunLengthEncoder::decode_u64(&encoded).unwrap();
353 assert_eq!(decoded, values);
354 }
355
356 #[test]
357 fn test_encode_u64_mixed_runs() {
358 let values = vec![1u64, 1, 1, 2, 2, 3];
359 let encoded = RunLengthEncoder::encode_u64(&values);
360 let decoded = RunLengthEncoder::decode_u64(&encoded).unwrap();
361 assert_eq!(decoded, values);
362 }
363
364 #[test]
365 fn test_encode_u64_max_value() {
366 let values = vec![u64::MAX, u64::MAX, u64::MAX];
367 let encoded = RunLengthEncoder::encode_u64(&values);
368 let decoded = RunLengthEncoder::decode_u64(&encoded).unwrap();
369 assert_eq!(decoded, values);
370 }
371
372 #[test]
373 fn test_encode_u64_large_roundtrip() {
374 let mut values = Vec::new();
375 for i in 0..100u64 {
376 for _ in 0..(i % 10 + 1) {
377 values.push(i * 1000);
378 }
379 }
380 let encoded = RunLengthEncoder::encode_u64(&values);
381 let decoded = RunLengthEncoder::decode_u64(&encoded).unwrap();
382 assert_eq!(decoded, values);
383 }
384
385 #[test]
386 fn test_decode_u64_invalid_length() {
387 let bad_data = vec![0u8; 11];
389 let result = RunLengthEncoder::decode_u64(&bad_data);
390 assert!(result.is_err());
391 }
392}