diff options
| -rw-r--r-- | Cargo.lock | 10 | ||||
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | examples/main.rs | 11 | ||||
| -rw-r--r-- | src/README | 3 | ||||
| -rw-r--r-- | src/lib.rs | 98 | ||||
| -rw-r--r-- | src/mod.rs | 3 |
6 files changed, 115 insertions, 14 deletions
@@ -3,19 +3,9 @@ version = 3 [[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] name = "ffi_demo" version = "0.1.0" dependencies = [ - "cc", "libc", ] @@ -2,12 +2,8 @@ name = "ffi_demo" version = "0.1.0" edition = "2021" -build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[build-dependencies] -cc = "1.0.79" - [dependencies] libc = "0.2.0" diff --git a/examples/main.rs b/examples/main.rs new file mode 100644 index 0000000..ca873a3 --- /dev/null +++ b/examples/main.rs @@ -0,0 +1,11 @@ +use libc::size_t; + +#[link(name = "snappy")] +extern { + fn snappy_max_compressed_length(source_length: size_t) -> size_t; +} + +fn main() { + let x = unsafe { snappy_max_compressed_length(100) }; + println!("max compressed length of a 100 byte buffer: {}", x); +}
\ No newline at end of file diff --git a/src/README b/src/README new file mode 100644 index 0000000..cc70725 --- /dev/null +++ b/src/README @@ -0,0 +1,3 @@ +```bash +sudo apt install libsnappy-dev +```
\ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e89b6d5 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,98 @@ +use libc::{c_int, size_t}; + +#[link(name = "snappy")] // 链接到 libsnappy.so + // 声明外部函数 +extern "C" { + // 外部函数与 C 语言的函数名 | 函数签名保持一致 + // c 的类型 通过 libc 包引入 + // 这里没有涉及指针等,较为简单 + fn snappy_compress( + input: *const u8, + input_length: size_t, + compressed: *mut u8, + compressed_length: *mut size_t, + ) -> c_int; // 压缩数据 + fn snappy_uncompress( + compressed: *const u8, + compressed_length: size_t, + uncompressed: *mut u8, + uncompressed_length: *mut size_t, + ) -> c_int; // 解压数据 + fn snappy_max_compressed_length(source_length: size_t) -> size_t; // 获取压缩后的最大长度 + fn snappy_uncompressed_length( + compressed: *const u8, + compressed_length: size_t, + result: *mut size_t, + ) -> c_int; // 获取解压后的长度 + fn snappy_validate_compressed_buffer(compressed: *const u8, compressed_length: size_t) + -> c_int; // 验证压缩数据 +} +/// 下面是真正给 rust 使用的接口函数 +pub(crate) fn validate_compressed_buffer(src: &[u8]) -> bool { + unsafe { snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0 } +} + +pub(crate) fn compress(src: &[u8]) -> Vec<u8> { + unsafe { + let srclen = src.len() as size_t; + let psrc = src.as_ptr(); + + let mut dstlen = snappy_max_compressed_length(srclen); + let mut dst = Vec::with_capacity(dstlen as usize); + let pdst = dst.as_mut_ptr(); + + snappy_compress(psrc, srclen, pdst, &mut dstlen); + dst.set_len(dstlen as usize); + dst + } +} + +pub(crate) fn uncompress(src: &[u8]) -> Option<Vec<u8>> { + unsafe { + let srclen = src.len() as size_t; + let psrc = src.as_ptr(); + + let mut dstlen: size_t = 0; + snappy_uncompressed_length(psrc, srclen, &mut dstlen); + + let mut dst = Vec::with_capacity(dstlen as usize); + let pdst = dst.as_mut_ptr(); + + if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 { + dst.set_len(dstlen as usize); + Some(dst) + } else { + None // SNAPPY_INVALID_INPUT + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn valid() { + let d = vec![0xde, 0xad, 0xd0, 0x0d]; + let c: &[u8] = &compress(&d); + assert!(validate_compressed_buffer(c)); + assert!(uncompress(c) == Some(d)); + } + + #[test] + fn invalid() { + let d = vec![0, 0, 0, 0]; + assert!(!validate_compressed_buffer(&d)); + assert!(uncompress(&d).is_none()); + } + + #[test] + fn empty() { + let d = vec![]; + assert!(!validate_compressed_buffer(&d)); + assert!(uncompress(&d).is_none()); + let c = compress(&d); + assert!(validate_compressed_buffer(&c)); + assert!(uncompress(&c) == Some(d)); + } +} diff --git a/src/mod.rs b/src/mod.rs new file mode 100644 index 0000000..8cf1617 --- /dev/null +++ b/src/mod.rs @@ -0,0 +1,3 @@ +pub use crate::lib::compress; +pub use crate::lib::uncompress; +pub use crate::lib::validate_compressed_buffer; |
