absperf_minilzo/
lib.rs

1//! High-level safe wrappers around minilzo, backed by the absperf-minilzo-sys crate.
2//! This was created instead of using existing crates because the existing crates didn't export all
3//! of the necessary functions (notably the adler32 checksum one and the version strings), and the
4//! interfaces weren't as flexible as they could have been.
5//!
6//! For the most part, to use this, just import [CompressInto] and [DecompressInto] and start using
7//! their methods on your byte slices.  For decompression into a new [std::vec::Vec], make sure you
8//! read the documentation on the [DecompressInto] implementation for Vec\<u8\>.
9
10mod checksum;
11mod compress;
12mod decompress;
13mod error;
14pub use checksum::{adler32, adler32_chain};
15pub use compress::CompressInto;
16pub use decompress::DecompressInto;
17use error::check;
18pub use error::{Error, Result};
19
20use absperf_minilzo_sys::{
21    __lzo_init_v2, lzo_callback_t, lzo_uint, lzo_version, lzo_version_date, lzo_version_string,
22};
23use std::ffi::{c_void, CStr};
24use std::mem::size_of;
25use std::os::raw::{c_char, c_int, c_long, c_short, c_uint};
26
27/// Run initialization, which currently just appears to be a simple pointer size check.
28/// You should probably still do this, just in case it gets more complex and necessary in the
29/// future or somehow the crate versions end up mixed up
30pub fn init() -> Result<()> {
31    let ret = unsafe {
32        __lzo_init_v2(
33            version_raw(),
34            size_of::<c_short>() as c_int,
35            size_of::<c_int>() as c_int,
36            size_of::<c_long>() as c_int,
37            size_of::<u32>() as c_int, // lzo_uint32_t
38            size_of::<lzo_uint>() as c_int,
39            size_of::<*mut c_char>() as c_int, // lzo_sizeof_dict_t
40            size_of::<*mut c_char>() as c_int,
41            size_of::<*mut c_void>() as c_int,
42            size_of::<lzo_callback_t>() as c_int,
43        )
44    };
45    check(ret)
46}
47
48/// Get the raw version as reported by minilzo
49pub fn version_raw() -> c_uint {
50    unsafe { lzo_version() }
51}
52
53/// Get the version as a (major, minor) tuple
54pub fn version() -> (u32, u32) {
55    // This computation is weird.  Not sure why the version is represented as a 16 bit integer with
56    // each component in the upper nibble.
57    let raw = version_raw();
58    (raw as u32 >> 12, (raw as u32 >> 4) & 0x0000000F)
59}
60
61/// Get the version as a string
62pub fn version_str() -> &'static str {
63    unsafe {
64        let cstr: &'static CStr = CStr::from_ptr(lzo_version_string());
65        cstr.to_str().unwrap()
66    }
67}
68
69/// Get the version date as a string
70pub fn version_date() -> &'static str {
71    unsafe {
72        let cstr: &'static CStr = CStr::from_ptr(lzo_version_date());
73        cstr.to_str().unwrap()
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    // Simple test to make sure a library function can be correctly called
82    #[test]
83    fn init() {
84        assert_eq!(super::init(), Ok(()));
85    }
86
87    #[test]
88    fn version() {
89        assert_eq!(version_raw(), 0x20a0);
90        assert_eq!(super::version(), (2, 10));
91        assert_eq!(version_str(), "2.10");
92        assert_eq!(version_date(), "Mar 01 2017");
93    }
94
95    #[test]
96    fn compress_slice() {
97        let source = include_bytes!("lorem.txt");
98        let mut compress_buffer = Vec::with_capacity(source.len());
99        compress_buffer.resize(source.len(), 0);
100        let mut decompress_buffer = compress_buffer.clone();
101
102        let compressed = source
103            .compress_into(compress_buffer.as_mut_slice())
104            .unwrap();
105        assert!(compressed.len() < source.len());
106
107        let decompressed = compressed
108            .decompress_into(decompress_buffer.as_mut_slice())
109            .unwrap();
110
111        assert_eq!(&source[..], decompressed);
112    }
113
114    #[test]
115    fn compress_vec() {
116        let source = include_bytes!("lorem.txt");
117        let mut compress_buffer = Vec::new();
118
119        let compressed = source.compress_into(&mut compress_buffer).unwrap();
120        assert!(compressed.len() < source.len());
121
122        let mut decompress_buffer = Vec::new();
123
124        let decompressed = compressed.decompress_into(&mut decompress_buffer).unwrap();
125
126        assert_eq!(&source[..], decompressed);
127    }
128}