1use std::io::{Error, ErrorKind, Result};
2
3use log::*;
4use lz4_sys::*;
5
6pub const ERR_LZ4_COMPRESS: &'static str = "lz4_compress_failed";
7pub const ERR_LZ4_CDECOMPRESS: &'static str = "lz4_decompress_failed";
8
9#[inline]
10pub fn compress_bound(size: i32) -> i32 {
11 unsafe { LZ4_compressBound(size) }
12}
13
14#[inline]
15pub fn compress(src: &[u8], dest: &mut [u8]) -> Result<i32> {
16 let compressed_len = unsafe {
17 LZ4_compress_default(
18 src.as_ptr() as *const libc::c_char,
19 dest.as_mut_ptr() as *mut libc::c_char,
20 src.len() as i32,
21 dest.len() as i32,
22 )
23 };
24 if compressed_len <= 0 {
25 trace!(
26 "compress fails: src len: {}, dest len : {}, compressed_len: {}",
27 src.len(),
28 dest.len(),
29 compressed_len
30 );
31 Err(Error::new(ErrorKind::Other, ERR_LZ4_COMPRESS))
32 } else {
33 Ok(compressed_len)
34 }
35}
36
37#[inline]
38pub fn decompress(src: &[u8], dest: &mut [u8]) -> Result<i32> {
39 let decompressed_len = unsafe {
40 LZ4_decompress_safe(
41 src.as_ptr() as *const libc::c_char,
42 dest.as_mut_ptr() as *mut libc::c_char,
43 src.len() as i32,
44 dest.len() as i32,
45 )
46 };
47 if decompressed_len <= 0 {
48 trace!(
49 "decompress fails: src len: {}, dest len : {}, decompressed_len: {}",
50 src.len(),
51 dest.len(),
52 decompressed_len
53 );
54 Err(Error::new(ErrorKind::Other, ERR_LZ4_CDECOMPRESS))
55 } else {
56 Ok(decompressed_len)
57 }
58}
59
60#[cfg(test)]
61mod tests {
62
63 use std::time::Instant;
64 use std::{
66 fs::File,
67 io::{Read, Write},
68 };
69
70 use super::{super::*, *};
71
72 #[test]
75 fn test_compress() {
76 let buf_len: usize = 16 * 1024;
77 let mut buffer = Buffer::alloc(buf_len).unwrap();
79 getrandom::getrandom(&mut buffer).unwrap();
80 let bound = compress_bound(buf_len as i32) as usize;
81 println!("compress_bound={}", bound);
82
83 let mut compressed_buffer = Buffer::alloc(bound).unwrap();
85 let compressed_len = compress(&buffer, &mut compressed_buffer).unwrap();
86 let mut _compressed_buffer = Buffer::alloc(compressed_len as usize).unwrap();
87 _compressed_buffer.copy_from(0, &compressed_buffer);
88 println!("compressed_len={}", _compressed_buffer.len());
89
90 let mut decompressed_buffer = Buffer::alloc(buf_len).unwrap();
92 decompressed_buffer.set_zero(0, decompressed_buffer.len());
93 let decompressed_len = decompress(&_compressed_buffer, &mut decompressed_buffer).unwrap();
94 println!("decompressed_len={}", decompressed_len);
95 assert_eq!(
96 &decompressed_buffer[0..decompressed_len as usize],
97 &buffer[0..]
98 );
99 }
100
101 #[test]
102 fn test_benchmark_compress() {
103 let loop_cnt: u64 = 1000000;
104 let mut buffer = Buffer::alloc(16 * 1024).unwrap();
106 getrandom::getrandom(&mut buffer).unwrap();
107 let mut bound = compress_bound(16 * 1024) as usize;
108 bound = (bound + 511) / 512 * 512;
109
110 let mut compressed_len = 0;
111 let start_ts = Instant::now();
113 for _i in 0..loop_cnt {
114 let mut compressed_buffer = Buffer::alloc(bound).unwrap();
115
116 let mut _compressed_len = compress(&buffer, &mut compressed_buffer).unwrap();
117 compressed_len = _compressed_len;
118 }
119 let end_ts = Instant::now();
120 println!(
122 "compressed_len={}. compress speed {}(byte)/sec",
123 compressed_len,
124 ((loop_cnt * 16 * 1024) as f64) / (end_ts.duration_since(start_ts).as_secs_f64())
125 );
126 }
127
128 #[test]
129 fn test_benchmark_decompress() {
130 let loop_cnt: u64 = 1000000;
131 let mut buffer = Buffer::alloc(16 * 1024).unwrap();
133 getrandom::getrandom(&mut buffer).unwrap();
134 let mut bound = compress_bound(16 * 1024) as usize;
135 println!("compress_bound={}", bound);
136
137 bound = (bound + 511) / 512 * 512;
138 let mut compressed_buffer = Buffer::alloc(bound).unwrap();
139 let compressed_len = compress(&buffer, &mut compressed_buffer).unwrap();
140
141 let mut decompressed_len = 0;
142 let start_ts = Instant::now();
144 for _i in 0..loop_cnt {
145 let mut decompressed_buffer = Buffer::alloc(16 * 1024).unwrap();
146
147 let _decompressed_len = decompress(
148 &compressed_buffer[0..compressed_len as usize],
149 &mut decompressed_buffer,
150 )
151 .unwrap();
152 decompressed_len = _decompressed_len;
153 }
154 let end_ts = Instant::now();
155 println!(
157 "decompressed_len={}. decompress speed {}(byte)/sec",
158 decompressed_len,
159 ((loop_cnt * 16 * 1024) as f64) / (end_ts.duration_since(start_ts).as_secs_f64())
160 );
161 }
162
163 #[allow(dead_code)]
165 fn test_compatibility() {
166 let mut src_buffer = Buffer::alloc(40 * 1024).unwrap();
167 let mut dst_buffer = Buffer::alloc(40 * 1024).unwrap();
168 let mut src_len: usize = 0;
169 let mut dst_len: usize = 0;
170 let mut compressed_buffer = Buffer::alloc(40 * 1024).unwrap();
171 let mut decompressed_buffer = Buffer::alloc(40 * 1024).unwrap();
172 {
173 let mut file = File::open("src.lz4").unwrap();
174 loop {
175 let size = file.read(&mut src_buffer[src_len..]).unwrap();
176 if size == 0 {
177 break;
178 }
179 src_len += size;
180 }
181 println!("src size={}", src_len);
182
183 let compressed_len = compress(&src_buffer, &mut compressed_buffer).unwrap();
184 println!("compressed len={}", compressed_len);
185
186 let mut file_res = File::create("dst.lz4.rust").unwrap();
187 file_res
188 .write_all(&mut compressed_buffer[0..compressed_len as usize])
189 .unwrap();
190 }
191 {
192 let mut file = File::open("dst.lz4").unwrap();
193 loop {
194 let size = file.read(&mut dst_buffer[dst_len..]).unwrap();
195 if size == 0 {
196 break;
197 }
198 dst_len += size;
199 }
200 println!("dst size={}", dst_len);
201 }
202
203 let decompressed_len =
204 decompress(&dst_buffer[0..dst_len], &mut decompressed_buffer).unwrap();
205 println!("decompressed_buffer size={}", decompressed_len);
206 assert_eq!(
207 &src_buffer[0..src_len],
208 &decompressed_buffer[0..decompressed_len as usize]
209 );
210 }
211}