1mod bitstream;
35mod decoder;
36mod encoder;
37mod error;
38pub mod params;
39mod preprocessor;
40
41pub use error::AecError;
42pub use params::{
43 AEC_ALLOW_K13, AEC_DATA_3BYTE, AEC_DATA_MSB, AEC_DATA_PREPROCESS, AEC_DATA_SIGNED,
44 AEC_NOT_ENFORCE, AEC_PAD_RSI, AEC_RESTRICTED, AecParams,
45};
46
47pub fn aec_compress(data: &[u8], params: &AecParams) -> Result<(Vec<u8>, Vec<u64>), AecError> {
53 params::validate(params)?;
54 encoder::encode(data, params, true)
55}
56
57pub fn aec_compress_no_offsets(data: &[u8], params: &AecParams) -> Result<Vec<u8>, AecError> {
59 params::validate(params)?;
60 let (bytes, _) = encoder::encode(data, params, false)?;
61 Ok(bytes)
62}
63
64pub fn aec_decompress(
68 data: &[u8],
69 expected_size: usize,
70 params: &AecParams,
71) -> Result<Vec<u8>, AecError> {
72 params::validate(params)?;
73 decoder::decode(data, expected_size, params)
74}
75
76pub fn aec_decompress_range(
83 data: &[u8],
84 block_offsets: &[u64],
85 byte_pos: usize,
86 byte_size: usize,
87 params: &AecParams,
88) -> Result<Vec<u8>, AecError> {
89 params::validate(params)?;
90 decoder::decode_range(data, block_offsets, byte_pos, byte_size, params)
91}
92
93#[cfg(test)]
96mod tests {
97 use super::*;
98
99 fn default_params(bits_per_sample: u32) -> AecParams {
100 AecParams {
101 bits_per_sample,
102 block_size: 16,
103 rsi: 128,
104 flags: AEC_DATA_PREPROCESS,
105 }
106 }
107
108 #[test]
109 fn round_trip_u8() {
110 let data: Vec<u8> = (0..1024).map(|i| (i % 256) as u8).collect();
111 let params = default_params(8);
112
113 let (compressed, offsets) = aec_compress(&data, ¶ms).unwrap();
114 assert!(!compressed.is_empty());
115 assert!(!offsets.is_empty());
116
117 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
118 assert_eq!(decompressed, data);
119 }
120
121 #[test]
122 fn round_trip_u16() {
123 let values: Vec<u16> = (0..2048).map(|i| (i * 7 % 65536) as u16).collect();
124 let data: Vec<u8> = values.iter().flat_map(|v| v.to_ne_bytes()).collect();
125 let params = default_params(16);
126
127 let (compressed, offsets) = aec_compress(&data, ¶ms).unwrap();
128 assert!(!compressed.is_empty());
129 assert!(!offsets.is_empty());
130
131 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
132 assert_eq!(decompressed, data);
133 }
134
135 #[test]
136 fn round_trip_u24() {
137 let n = 4096;
138 let data: Vec<u8> = (0..n * 3).map(|i| (i % 256) as u8).collect();
139 let params = default_params(24);
140
141 let (compressed, offsets) = aec_compress(&data, ¶ms).unwrap();
142 assert!(!compressed.is_empty());
143 assert!(!offsets.is_empty());
144
145 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
146 assert_eq!(decompressed, data);
147 }
148
149 #[test]
150 fn round_trip_u32() {
151 let values: Vec<u32> = (0..4096).map(|i| i * 13).collect();
152 let data: Vec<u8> = values.iter().flat_map(|v| v.to_ne_bytes()).collect();
153 let params = default_params(32);
154
155 let (compressed, offsets) = aec_compress(&data, ¶ms).unwrap();
156 assert!(!compressed.is_empty());
157 assert!(!offsets.is_empty());
158
159 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
160 assert_eq!(decompressed, data);
161 }
162
163 #[test]
164 fn empty_input_returns_empty() {
165 let params = default_params(8);
166 let (compressed, offsets) = aec_compress(&[], ¶ms).unwrap();
167 assert!(compressed.is_empty());
168 assert!(offsets.is_empty());
169
170 let decompressed = aec_decompress(&[], 0, ¶ms).unwrap();
171 assert!(decompressed.is_empty());
172 }
173
174 #[test]
175 fn misaligned_data_returns_error() {
176 let data = vec![1u8, 2, 3]; let params = default_params(16);
178 assert!(aec_compress(&data, ¶ms).is_err());
179 }
180
181 #[test]
182 fn offsets_match_rsi_count() {
183 let data: Vec<u8> = (0..4096).map(|i| (i % 256) as u8).collect();
185 let params = default_params(8);
186 let (_, offsets) = aec_compress(&data, ¶ms).unwrap();
187 let expected_rsis = 4096usize.div_ceil(128 * 16);
188 assert_eq!(offsets.len(), expected_rsis);
189 }
190
191 #[test]
192 fn round_trip_constant_data() {
193 let data = vec![42u8; 2048];
194 let params = default_params(8);
195
196 let (compressed, _) = aec_compress(&data, ¶ms).unwrap();
197 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
198 assert_eq!(decompressed, data);
199 }
200
201 #[test]
202 fn round_trip_no_preprocess() {
203 let data: Vec<u8> = (0..1024).map(|i| (i % 256) as u8).collect();
204 let params = AecParams {
205 bits_per_sample: 8,
206 block_size: 16,
207 rsi: 128,
208 flags: 0, };
210
211 let (compressed, _) = aec_compress(&data, ¶ms).unwrap();
212 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
213 assert_eq!(decompressed, data);
214 }
215
216 #[test]
217 fn range_decode_matches_full() {
218 let data: Vec<u8> = (0..4096).map(|i| (i % 256) as u8).collect();
219 let params = default_params(8);
220
221 let (compressed, offsets) = aec_compress(&data, ¶ms).unwrap();
222 let full = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
223
224 let pos = 100;
226 let size = 200;
227 let partial = aec_decompress_range(&compressed, &offsets, pos, size, ¶ms).unwrap();
228
229 assert_eq!(partial.len(), size);
230 assert_eq!(&partial[..], &full[pos..pos + size]);
231 }
232
233 #[test]
234 fn range_decode_first_block() {
235 let data: Vec<u8> = (0..4096).map(|i| (i % 256) as u8).collect();
236 let params = default_params(8);
237
238 let (compressed, offsets) = aec_compress(&data, ¶ms).unwrap();
239 let full = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
240
241 let partial = aec_decompress_range(&compressed, &offsets, 0, 50, ¶ms).unwrap();
242 assert_eq!(&partial[..], &full[..50]);
243 }
244
245 #[test]
246 fn range_decode_zero_size() {
247 let data: Vec<u8> = (0..1024).map(|i| (i % 256) as u8).collect();
248 let params = default_params(8);
249
250 let (compressed, offsets) = aec_compress(&data, ¶ms).unwrap();
251
252 let partial = aec_decompress_range(&compressed, &offsets, 0, 0, ¶ms).unwrap();
253 assert!(partial.is_empty());
254 }
255
256 #[test]
257 fn round_trip_msb_data() {
258 let data: Vec<u8> = (0..1024).map(|i| (i % 256) as u8).collect();
259 let params = AecParams {
260 bits_per_sample: 8,
261 block_size: 16,
262 rsi: 128,
263 flags: AEC_DATA_PREPROCESS | AEC_DATA_MSB,
264 };
265
266 let (compressed, _) = aec_compress(&data, ¶ms).unwrap();
267 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
268 assert_eq!(decompressed, data);
269 }
270
271 #[test]
272 fn round_trip_small_block_size() {
273 let data: Vec<u8> = (0..512).map(|i| (i % 256) as u8).collect();
274 let params = AecParams {
275 bits_per_sample: 8,
276 block_size: 8,
277 rsi: 64,
278 flags: AEC_DATA_PREPROCESS,
279 };
280
281 let (compressed, _) = aec_compress(&data, ¶ms).unwrap();
282 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
283 assert_eq!(decompressed, data);
284 }
285
286 #[test]
289 fn compress_no_offsets_round_trip() {
290 let data: Vec<u8> = (0..2048).map(|i| (i % 256) as u8).collect();
291 let params = default_params(8);
292
293 let compressed = aec_compress_no_offsets(&data, ¶ms).unwrap();
294 assert!(!compressed.is_empty());
295
296 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
297 assert_eq!(decompressed, data);
298 }
299
300 #[test]
301 fn compress_no_offsets_empty() {
302 let params = default_params(8);
303 let compressed = aec_compress_no_offsets(&[], ¶ms).unwrap();
304 assert!(compressed.is_empty());
305 }
306
307 #[test]
310 fn round_trip_signed_8bit() {
311 let data: Vec<u8> = (-128..=127i8).map(|v| v as u8).collect();
313 let params = AecParams {
314 bits_per_sample: 8,
315 block_size: 16,
316 rsi: 128,
317 flags: AEC_DATA_PREPROCESS | AEC_DATA_SIGNED,
318 };
319
320 let (compressed, _) = aec_compress(&data, ¶ms).unwrap();
321 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
322 assert_eq!(decompressed, data);
323 }
324
325 #[test]
328 fn range_decode_oob_rsi_returns_error() {
329 let data: Vec<u8> = (0..1024).map(|i| (i % 256) as u8).collect();
330 let params = default_params(8);
331 let (compressed, offsets) = aec_compress(&data, ¶ms).unwrap();
332
333 let result = aec_decompress_range(&compressed, &offsets, 999999, 100, ¶ms);
335 assert!(result.is_err());
336 }
337
338 #[test]
339 fn range_decode_empty_data_returns_error() {
340 let params = default_params(8);
341 let result = aec_decompress_range(&[], &[0], 0, 100, ¶ms);
342 assert!(result.is_err());
343 }
344
345 #[test]
348 fn compress_bad_rsi_returns_error() {
349 let params = AecParams {
350 bits_per_sample: 8,
351 block_size: 16,
352 rsi: 0, flags: 0,
354 };
355 assert!(aec_compress(&[0u8; 256], ¶ms).is_err());
356 }
357
358 #[test]
359 fn decompress_bad_block_size_returns_error() {
360 let params = AecParams {
361 bits_per_sample: 8,
362 block_size: 12, rsi: 128,
364 flags: 0,
365 };
366 assert!(aec_decompress(&[0u8; 256], 256, ¶ms).is_err());
367 }
368
369 #[test]
370 fn compress_restricted_high_bps_returns_error() {
371 let params = AecParams {
372 bits_per_sample: 8,
373 block_size: 16,
374 rsi: 128,
375 flags: AEC_RESTRICTED, };
377 assert!(aec_compress(&[0u8; 256], ¶ms).is_err());
378 }
379
380 #[test]
383 fn round_trip_u32_max_values() {
384 let values: Vec<u32> = vec![0, u32::MAX, u32::MAX / 2, 1, u32::MAX - 1];
386 let data: Vec<u8> = values.iter().flat_map(|v| v.to_ne_bytes()).collect();
387 let params = default_params(32);
388
389 let (compressed, _) = aec_compress(&data, ¶ms).unwrap();
390 let decompressed = aec_decompress(&compressed, data.len(), ¶ms).unwrap();
391 assert_eq!(decompressed, data);
392 }
393}