io_buffer/compress/
lz4.rs

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