oxihuman_core/
compression_zstd.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9pub struct ZstdConfig {
10 pub level: i32,
11 pub checksum: bool,
12}
13
14impl Default for ZstdConfig {
15 fn default() -> Self {
16 Self {
17 level: 3,
18 checksum: true,
19 }
20 }
21}
22
23#[derive(Debug, Clone)]
25pub struct ZstdCompressor {
26 pub config: ZstdConfig,
27}
28
29impl ZstdCompressor {
30 pub fn new(config: ZstdConfig) -> Self {
31 Self { config }
32 }
33
34 pub fn default_compressor() -> Self {
35 Self::new(ZstdConfig::default())
36 }
37
38 pub fn with_level(level: i32) -> Self {
39 Self::new(ZstdConfig {
40 level,
41 checksum: true,
42 })
43 }
44}
45
46pub fn zstd_compress(data: &[u8]) -> Vec<u8> {
48 let mut out = Vec::with_capacity(data.len() + 4);
50 out.extend_from_slice(&(data.len() as u32).to_le_bytes());
51 out.extend_from_slice(data);
52 out
53}
54
55pub fn zstd_decompress(data: &[u8]) -> Result<Vec<u8>, String> {
57 if data.len() < 4 {
59 return Err("zstd: input too short".to_string());
60 }
61 let expected = u32::from_le_bytes(data[..4].try_into().unwrap_or_default()) as usize;
62 let payload = &data[4..];
63 if payload.len() < expected {
64 return Err("zstd: truncated data".to_string());
65 }
66 Ok(payload[..expected].to_vec())
67}
68
69pub fn zstd_frame_size_estimate(input_len: usize) -> usize {
71 input_len + 12
72}
73
74pub fn zstd_frame_valid(data: &[u8]) -> bool {
76 data.len() >= 4
77}
78
79pub fn zstd_roundtrip_ok(data: &[u8]) -> bool {
81 zstd_decompress(&zstd_compress(data))
82 .map(|d| d == data)
83 .unwrap_or(false)
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_default_level() {
92 assert_eq!(ZstdConfig::default().level, 3);
94 }
95
96 #[test]
97 fn test_with_level() {
98 let c = ZstdCompressor::with_level(9);
100 assert_eq!(c.config.level, 9);
101 }
102
103 #[test]
104 fn test_compress_empty() {
105 assert_eq!(zstd_compress(&[]).len(), 4);
107 }
108
109 #[test]
110 fn test_roundtrip_hello() {
111 assert!(zstd_roundtrip_ok(b"hello zstd"));
113 }
114
115 #[test]
116 fn test_roundtrip_binary() {
117 let data: Vec<u8> = (0u8..128).collect();
119 assert!(zstd_roundtrip_ok(&data));
120 }
121
122 #[test]
123 fn test_decompress_short() {
124 assert!(zstd_decompress(&[1, 2]).is_err());
126 }
127
128 #[test]
129 fn test_frame_size_estimate() {
130 assert!(zstd_frame_size_estimate(100) > 100);
132 }
133
134 #[test]
135 fn test_frame_valid() {
136 assert!(zstd_frame_valid(&[0, 0, 0, 0]));
138 assert!(!zstd_frame_valid(&[0]));
139 }
140
141 #[test]
142 fn test_checksum_default() {
143 assert!(ZstdConfig::default().checksum);
145 }
146}