Skip to main content

clickhouse_driver_lz4/
lib.rs

1#![no_std]
2extern crate libc;
3#[cfg(test)]
4#[macro_use]
5extern crate std;
6
7use libc::{c_char, c_int, c_uint, size_t};
8
9pub type LZ4FErrorCode = size_t;
10pub const LZ4F_VERSION: c_uint = 100;
11
12extern "C" {
13    // int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize);
14    #[allow(non_snake_case)]
15    pub fn LZ4_compress_default(
16        source: *const c_char,
17        dest: *mut c_char,
18        sourceSize: c_int,
19        maxDestSize: c_int,
20    ) -> c_int;
21
22    // int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration);
23    #[allow(non_snake_case)]
24    pub fn LZ4_compress_fast(
25        source: *const c_char,
26        dest: *mut c_char,
27        sourceSize: c_int,
28        maxDestSize: c_int,
29        acceleration: c_int,
30    ) -> c_int;
31
32    // int LZ4_compress_HC (const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel);
33    #[allow(non_snake_case)]
34    pub fn LZ4_compress_HC(
35        src: *const c_char,
36        dst: *mut c_char,
37        srcSize: c_int,
38        dstCapacity: c_int,
39        compressionLevel: c_int,
40    ) -> c_int;
41
42    // int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
43    #[allow(non_snake_case)]
44    pub fn LZ4_decompress_safe(
45        source: *const c_char,
46        dest: *mut c_char,
47        compressedSize: c_int,
48        maxDecompressedSize: c_int,
49    ) -> c_int;
50
51    #[allow(non_snake_case)]
52    pub fn LZ4_decompress_fast(
53        source: *const c_char,
54        dest: *mut c_char,
55        originaldSize: c_int,
56    ) -> c_int;
57
58    // const char* LZ4F_getErrorName(LZ4F_errorCode_t code);
59    pub fn LZ4F_getErrorName(code: size_t) -> *const c_char;
60
61    // int LZ4_versionNumber(void)
62    pub fn LZ4_versionNumber() -> c_int;
63
64    // int LZ4_compressBound(int isize)
65    fn LZ4_compressBound(size: c_int) -> c_int;
66
67}
68
69const LZ4_DISTANCE_MAX: usize = 65535;
70
71#[allow(non_snake_case)]
72#[inline]
73pub const fn LZ4_CompressInplaceBufferSize(decompressed: usize) -> usize {
74    decompressed + LZ4_DISTANCE_MAX + 32
75}
76
77#[allow(non_snake_case)]
78#[inline]
79pub const fn LZ4_DecompressInplaceBufferSize(compressed: usize) -> usize {
80    compressed + (compressed >> 8) + 32
81}
82
83#[allow(non_snake_case)]
84#[inline]
85pub fn LZ4_Decompress(src: &[u8], dst: &mut [u8]) -> i32 {
86    unsafe {
87        LZ4_decompress_safe(
88            src.as_ptr() as *const c_char,
89            dst.as_mut_ptr() as *mut c_char,
90            src.len() as c_int,
91            dst.len() as c_int,
92        )
93    }
94}
95
96#[allow(non_snake_case)]
97#[inline]
98pub fn LZ4_Compress(src: &[u8], dst: &mut [u8]) -> i32 {
99    unsafe {
100        LZ4_compress_default(
101            src.as_ptr() as *const c_char,
102            dst.as_mut_ptr() as *mut c_char,
103            src.len() as c_int,
104            dst.len() as c_int,
105        )
106    }
107}
108
109#[allow(non_snake_case)]
110#[inline]
111pub fn LZ4_CompressBounds(src: usize) -> usize {
112    unsafe { LZ4_compressBound(src as c_int) as usize }
113}
114
115#[cfg(test)]
116mod test {
117    extern crate rand;
118    use self::rand::RngCore;
119    use crate::*;
120    use libc::c_int;
121
122    #[test]
123    fn test_version_number() {
124        let version = unsafe { LZ4_versionNumber() };
125        assert_eq!(version, 10902 as c_int);
126
127        // 640 kb original size
128        assert_eq!(unsafe { LZ4_compressBound(640 * 1024) }, 657946);
129
130        // 1Mb destination bufer
131        assert_eq!(LZ4_CompressInplaceBufferSize(983009), 1024 * 1024);
132        assert_eq!(LZ4_DecompressInplaceBufferSize(1044464), 1024 * 1024 - 1);
133    }
134
135    #[test]
136    fn test_compression() {
137        use std::vec::Vec;
138        let mut rng = rand::thread_rng();
139
140        for sz in [600_usize, 1024, 6000, 65000, 650000].iter() {
141            let cz: usize = LZ4_CompressInplaceBufferSize(*sz);
142
143            let mut orig: Vec<u8> = Vec::with_capacity(cz);
144            unsafe {
145                orig.set_len(cz);
146                rng.fill_bytes(&mut orig[..]);
147
148                let margin = cz - *sz;
149                //compress inplace
150                //maximum compressed size
151                let bz = LZ4_compressBound(*sz as c_int);
152                //destination compression bufer
153                let mut comp: Vec<u8> = Vec::with_capacity(bz as usize);
154
155                comp.set_len(bz as usize);
156
157                //normal compression
158                let code = LZ4_compress_default(
159                    orig.as_ptr().add(margin) as *const c_char,
160                    comp.as_mut_ptr() as *mut c_char,
161                    (orig.len() - margin) as i32,
162                    comp.len() as i32,
163                );
164
165                assert!(code >= 0);
166                assert_eq!(orig.len() - margin, *sz);
167                let compressed_sz = code as usize;
168
169                //compression inplace
170                let code = LZ4_compress_default(
171                    orig.as_ptr().add(margin) as *const c_char,
172                    orig.as_mut_ptr() as *mut c_char,
173                    (orig.len() - margin) as i32,
174                    orig.len() as i32,
175                );
176
177                assert!(code >= 0);
178
179                assert_eq!(&comp[0..compressed_sz], &orig[0..compressed_sz]);
180            }
181        }
182
183        assert_eq!(1, 1);
184    }
185
186    #[test]
187    fn test_decompression() {
188        use std::vec::Vec;
189        //let mut rng = rand::thread_rng();
190
191        for sz in [600_usize, 1024, 6000, 65000, 650000].iter() {
192            let mut orig: Vec<u8> = Vec::with_capacity(*sz);
193            unsafe {
194                orig.set_len(*sz);
195
196                {
197                    //it's sort of randomized data
198                    orig[0] = 1;
199                    orig[*sz / 4] = 4;
200                    orig[*sz / 2] = 7;
201                    orig[*sz * 2 / 3] = 10;
202                    orig[*sz - 1] = 1;
203                }
204
205                let bz = LZ4_compressBound(*sz as c_int) as usize;
206
207                let mut comp: Vec<u8> = Vec::with_capacity(bz);
208                comp.set_len(bz);
209
210                let code = LZ4_compress_default(
211                    orig.as_ptr() as *const c_char,
212                    comp.as_mut_ptr() as *mut c_char,
213                    (orig.len()) as i32,
214                    (bz) as i32,
215                );
216
217                assert!(code > 0);
218                //size of compressed data
219                println!(
220                    "orig {}; compressed {}; in buf len {}",
221                    *sz,
222                    code as usize,
223                    comp.len()
224                );
225                //compressed size
226                let cz = code as usize;
227
228                let mut buf: Vec<u8> = Vec::with_capacity(*sz);
229                buf.set_len(*sz);
230
231                let code = LZ4_decompress_safe(
232                    comp.as_ptr() as *const c_char,
233                    buf.as_mut_ptr() as *mut c_char,
234                    cz as i32,
235                    *sz as i32,
236                );
237
238                assert!(code > 0);
239
240                let cz = code as usize;
241
242                assert_eq!(cz, *sz);
243                assert_eq!(&orig[0..*sz], &buf[0..cz]);
244            }
245        }
246    }
247}