summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml4
-rw-r--r--examples/main.rs11
-rw-r--r--src/README3
-rw-r--r--src/lib.rs98
-rw-r--r--src/mod.rs3
6 files changed, 115 insertions, 14 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 77bc8ac..3775cdc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
]
diff --git a/Cargo.toml b/Cargo.toml
index 483ce07..e470b98 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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;