From c7678bd2998368d1683c0f012bd1f671c13e2fc0 Mon Sep 17 00:00:00 2001 From: Artavazd Balaian Date: Mon, 13 Mar 2023 20:05:29 +0800 Subject: [PATCH 1/7] feat: Add WASM support (target `wasm32-unknown-unknown`) inspired by zstd-rs (https://github.com/gyscos/zstd-rs/pull/139) --- README.md | 15 ++++++++++ bzip2-sys/Cargo.toml | 2 ++ bzip2-sys/build.rs | 41 ++++++++++++++++++++++++-- bzip2-sys/bzlib.h | 15 ++++++++++ bzip2-sys/examples/it_work.rs | 35 ++++++++++++++++++++++ bzip2-sys/lib.rs | 7 +++++ bzip2-sys/wasm-shim/stdlib.h | 22 ++++++++++++++ bzip2-sys/wasm-shim/string.h | 22 ++++++++++++++ bzip2-sys/wasm_shim.rs | 55 +++++++++++++++++++++++++++++++++++ 9 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 bzip2-sys/bzlib.h create mode 100644 bzip2-sys/examples/it_work.rs create mode 100644 bzip2-sys/wasm-shim/stdlib.h create mode 100644 bzip2-sys/wasm-shim/string.h create mode 100644 bzip2-sys/wasm_shim.rs diff --git a/README.md b/README.md index 52177323..0a886392 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,21 @@ A streaming compression/decompression library for rust with bindings to libbz2. bzip2 = "0.4" ``` +## WASM +bzip2-rs can be compiled to WASM. Make sure you added `wasm32-unknown-unknown` target +```bash +rustup target add wasm32-unknown-unknown +``` +To build and run WASM example make sure that you working directory in terminal is `bzip2-sys` +### Build WASM target +```bash +cargo build --target wasm32-unknown-unknown --no-default-features --example it_work +``` + +### Run WASM target using wasmtime +```bash +wasmtime ..\target\wasm32-unknown-unknown\debug\examples\it_work.wasm --invoke test_decompress +``` # License diff --git a/bzip2-sys/Cargo.toml b/bzip2-sys/Cargo.toml index bc2318f6..4b3973e6 100644 --- a/bzip2-sys/Cargo.toml +++ b/bzip2-sys/Cargo.toml @@ -28,3 +28,5 @@ cc = "1.0" [features] # Enable this feature if you want to have a statically linked bzip2 static = [] +std = [] # Use std types instead of libc in bindgen + diff --git a/bzip2-sys/build.rs b/bzip2-sys/build.rs index feb004ca..55ac5b39 100644 --- a/bzip2-sys/build.rs +++ b/bzip2-sys/build.rs @@ -2,7 +2,7 @@ extern crate cc; extern crate pkg_config; use std::path::PathBuf; -use std::{env, fs}; +use std::{env, fmt, fs}; fn main() { let mut cfg = cc::Build::new(); @@ -23,6 +23,29 @@ fn main() { } } + // List out the WASM targets that need wasm-shim. + // Note that Emscripten already provides its own C standard library so + // wasm32-unknown-emscripten should not be included here. + // See: https://github.com/gyscos/zstd-rs/pull/209 + let need_wasm_shim = env::var("TARGET").map_or(false, |target| { + target == "wasm32-unknown-unknown" || target == "wasm32-wasi" + }); + + if need_wasm_shim { + cargo_print(&"rerun-if-changed=wasm-shim/stdlib.h"); + cargo_print(&"rerun-if-changed=wasm-shim/string.h"); + + cfg.include("wasm-shim/"); + cfg.define("XXH_STATIC_ASSERT", Some("0")); + cfg.opt_level(3); + } + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + + if target_arch == "wasm32" || target_os == "hermit" { + cargo_print(&"rustc-cfg=feature=\"std\""); + } + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); cfg.include("bzip2-1.0.8") @@ -42,6 +65,18 @@ fn main() { let include = dst.join("include"); fs::create_dir_all(&include).unwrap(); fs::copy(src.join("bzlib.h"), dst.join("include/bzlib.h")).unwrap(); - println!("cargo:root={}", dst.display()); - println!("cargo:include={}", dst.join("include").display()); + cargo_print(&format_args!("cargo:root={}", dst.display())); + cargo_print(&format_args!( + "cargo:include={}", + dst.join("include").display() + )); +} + +/// Print a line for cargo. +/// +/// If non-cargo is set, do not print anything. +fn cargo_print(content: &dyn fmt::Display) { + if cfg!(not(feature = "non-cargo")) { + println!("cargo:{}", content); + } } diff --git a/bzip2-sys/bzlib.h b/bzip2-sys/bzlib.h new file mode 100644 index 00000000..f91ae837 --- /dev/null +++ b/bzip2-sys/bzlib.h @@ -0,0 +1,15 @@ +#ifdef PKG_CONFIG + +/* Just use installed headers */ +#include + +#else // #ifdef PKG_CONFIG + +#include "bzip2-1.0.8/bzlib.h" + +#endif // #ifdef PKG_CONFIG + + +/* This file is used to generate bindings for both headers. + * Check update_bindings.sh to see how to use it. + * Or use the `bindgen` feature, which will create the bindings automatically. */ diff --git a/bzip2-sys/examples/it_work.rs b/bzip2-sys/examples/it_work.rs new file mode 100644 index 00000000..af92f004 --- /dev/null +++ b/bzip2-sys/examples/it_work.rs @@ -0,0 +1,35 @@ +#[cfg(feature = "std")] +use std::os::raw::{c_char, c_int, c_uint}; + +#[cfg(not(feature = "std"))] +use libc::{c_char, c_int, c_uint}; + +#[no_mangle] +pub extern "C" fn test_decompress() -> bool { + let uncompressed_bytes = include_bytes!("../bzip2-1.0.8/sample1.ref"); + let compressed_bytes = include_bytes!("../bzip2-1.0.8/sample1.bz2"); + let mut raw: Box = unsafe { Box::new(std::mem::zeroed()) }; + let mut buf: [u8; 100352] = [0; 98 * 1024]; + unsafe { + assert_eq!(bzip2_sys::BZ2_bzDecompressInit(&mut *raw, 0, 0 as c_int), 0); + raw.next_in = compressed_bytes.as_ptr() as *mut c_char; + raw.avail_in = compressed_bytes.len().min(c_uint::MAX as usize) as c_uint; + + raw.next_out = buf.as_mut_ptr() as *mut c_char; + raw.avail_out = buf.len() as c_uint; + assert_eq!( + bzip2_sys::BZ2_bzDecompress(&mut *raw), + bzip2_sys::BZ_STREAM_END + ); + bzip2_sys::BZ2_bzDecompressEnd(&mut *raw); + }; + let total_out = ((raw.total_out_lo32 as u64) | ((raw.total_out_hi32 as u64) << 32)) as usize; + assert_eq!(total_out, uncompressed_bytes.len()); + + let slice: &[u8] = buf[0..total_out].as_ref(); + assert_eq!(uncompressed_bytes, slice); + + return true; +} + +fn main() {} diff --git a/bzip2-sys/lib.rs b/bzip2-sys/lib.rs index 54d08053..84f7b7b9 100644 --- a/bzip2-sys/lib.rs +++ b/bzip2-sys/lib.rs @@ -2,6 +2,13 @@ extern crate libc; +#[cfg(target_arch = "wasm32")] +mod wasm_shim; + +#[cfg(feature = "std")] +use std::os::raw::{c_char, c_int, c_uint, c_void}; + +#[cfg(not(feature = "std"))] use libc::{c_char, c_int, c_uint, c_void}; pub const BZ_RUN: c_int = 0; diff --git a/bzip2-sys/wasm-shim/stdlib.h b/bzip2-sys/wasm-shim/stdlib.h new file mode 100644 index 00000000..be102cc2 --- /dev/null +++ b/bzip2-sys/wasm-shim/stdlib.h @@ -0,0 +1,22 @@ +#include + +#ifndef _STDLIB_H +#define _STDLIB_H 1 + +void *rust_zstd_wasm_shim_malloc(size_t size); +void *rust_zstd_wasm_shim_calloc(size_t nmemb, size_t size); +void rust_zstd_wasm_shim_free(void *ptr); + +inline void *malloc(size_t size) { + return rust_zstd_wasm_shim_malloc(size); +} + +inline void *calloc(size_t nmemb, size_t size) { + return rust_zstd_wasm_shim_calloc(nmemb, size); +} + +inline void free(void *ptr) { + rust_zstd_wasm_shim_free(ptr); +} + +#endif // _STDLIB_H diff --git a/bzip2-sys/wasm-shim/string.h b/bzip2-sys/wasm-shim/string.h new file mode 100644 index 00000000..b0abf79c --- /dev/null +++ b/bzip2-sys/wasm-shim/string.h @@ -0,0 +1,22 @@ +#include + +#ifndef _STRING_H +#define _STRING_H 1 + +void *rust_zstd_wasm_shim_memcpy(void *restrict dest, const void *restrict src, size_t n); +void *rust_zstd_wasm_shim_memmove(void *dest, const void *src, size_t n); +void *rust_zstd_wasm_shim_memset(void *dest, int c, size_t n); + +inline void *memcpy(void *restrict dest, const void *restrict src, size_t n) { + return rust_zstd_wasm_shim_memcpy(dest, src, n); +} + +inline void *memmove(void *dest, const void *src, size_t n) { + return rust_zstd_wasm_shim_memmove(dest, src, n); +} + +inline void *memset(void *dest, int c, size_t n) { + return rust_zstd_wasm_shim_memset(dest, c, n); +} + +#endif // _STRING_H diff --git a/bzip2-sys/wasm_shim.rs b/bzip2-sys/wasm_shim.rs new file mode 100644 index 00000000..8bfd7baf --- /dev/null +++ b/bzip2-sys/wasm_shim.rs @@ -0,0 +1,55 @@ +use std::alloc::{alloc, dealloc, Layout}; +use std::os::raw::{c_int, c_void}; + +#[no_mangle] +pub extern "C" fn rust_zstd_wasm_shim_malloc(size: usize) -> *mut c_void { + unsafe { + let layout = Layout::from_size_align_unchecked(size, 1); + alloc(layout).cast() + } +} + +#[no_mangle] +pub extern "C" fn rust_zstd_wasm_shim_calloc(nmemb: usize, size: usize) -> *mut c_void { + unsafe { + let layout = Layout::from_size_align_unchecked(size * nmemb, 1); + alloc(layout).cast() + } +} + +#[no_mangle] +pub unsafe extern "C" fn rust_zstd_wasm_shim_free(ptr: *mut c_void) { + // layout is not actually used + let layout = Layout::from_size_align_unchecked(1, 1); + dealloc(ptr.cast(), layout); +} + +#[no_mangle] +pub unsafe extern "C" fn rust_zstd_wasm_shim_memcpy( + dest: *mut c_void, + src: *const c_void, + n: usize, +) -> *mut c_void { + std::ptr::copy_nonoverlapping(src as *const u8, dest as *mut u8, n); + dest +} + +#[no_mangle] +pub unsafe extern "C" fn rust_zstd_wasm_shim_memmove( + dest: *mut c_void, + src: *const c_void, + n: usize, +) -> *mut c_void { + std::ptr::copy(src as *const u8, dest as *mut u8, n); + dest +} + +#[no_mangle] +pub unsafe extern "C" fn rust_zstd_wasm_shim_memset( + dest: *mut c_void, + c: c_int, + n: usize, +) -> *mut c_void { + std::ptr::write_bytes(dest as *mut u8, c as u8, n); + dest +} From b0339068ee912890a92afe00a18e303aa4ebcc5e Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Wed, 23 Aug 2023 17:34:19 +0200 Subject: [PATCH 2/7] make it compile with wasm32-unknown-unknown --- Cargo.toml | 1 - src/lib.rs | 1 - src/mem.rs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9ed446cc..b4584ce1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ categories = ["compression", "api-bindings"] [workspace] [dependencies] -libc = "0.2" bzip2-sys = { version = "0.1.11", path = "bzip2-sys" } tokio-io = { version = "0.1", optional = true } futures = { version = "0.1", optional = true } diff --git a/src/lib.rs b/src/lib.rs index 4eb97fc7..519a27f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,6 @@ #![doc(html_root_url = "https://docs.rs/bzip2/")] extern crate bzip2_sys as ffi; -extern crate libc; #[cfg(test)] extern crate partial_io; #[cfg(test)] diff --git a/src/mem.rs b/src/mem.rs index ff7d9a5a..c9410528 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -6,7 +6,7 @@ use std::marker; use std::mem; use std::slice; -use libc::{c_int, c_uint}; +use std::os::raw::{c_int, c_uint}; use {ffi, Compression}; From d3aa5f8bc0b823fbe1ac50db71d303c24f98c275 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Wed, 23 Aug 2023 17:35:34 +0200 Subject: [PATCH 3/7] fix up the shim names --- bzip2-sys/wasm-shim/stdlib.h | 12 ++++++------ bzip2-sys/wasm-shim/string.h | 12 ++++++------ bzip2-sys/wasm_shim.rs | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/bzip2-sys/wasm-shim/stdlib.h b/bzip2-sys/wasm-shim/stdlib.h index be102cc2..1b0c1116 100644 --- a/bzip2-sys/wasm-shim/stdlib.h +++ b/bzip2-sys/wasm-shim/stdlib.h @@ -3,20 +3,20 @@ #ifndef _STDLIB_H #define _STDLIB_H 1 -void *rust_zstd_wasm_shim_malloc(size_t size); -void *rust_zstd_wasm_shim_calloc(size_t nmemb, size_t size); -void rust_zstd_wasm_shim_free(void *ptr); +void *rust_bzip2_wasm_shim_malloc(size_t size); +void *rust_bzip2_wasm_shim_calloc(size_t nmemb, size_t size); +void rust_bzip2_wasm_shim_free(void *ptr); inline void *malloc(size_t size) { - return rust_zstd_wasm_shim_malloc(size); + return rust_bzip2_wasm_shim_malloc(size); } inline void *calloc(size_t nmemb, size_t size) { - return rust_zstd_wasm_shim_calloc(nmemb, size); + return rust_bzip2_wasm_shim_calloc(nmemb, size); } inline void free(void *ptr) { - rust_zstd_wasm_shim_free(ptr); + rust_bzip2_wasm_shim_free(ptr); } #endif // _STDLIB_H diff --git a/bzip2-sys/wasm-shim/string.h b/bzip2-sys/wasm-shim/string.h index b0abf79c..6042c872 100644 --- a/bzip2-sys/wasm-shim/string.h +++ b/bzip2-sys/wasm-shim/string.h @@ -3,20 +3,20 @@ #ifndef _STRING_H #define _STRING_H 1 -void *rust_zstd_wasm_shim_memcpy(void *restrict dest, const void *restrict src, size_t n); -void *rust_zstd_wasm_shim_memmove(void *dest, const void *src, size_t n); -void *rust_zstd_wasm_shim_memset(void *dest, int c, size_t n); +void *rust_bzip2_wasm_shim_memcpy(void *restrict dest, const void *restrict src, size_t n); +void *rust_bzip2_wasm_shim_memmove(void *dest, const void *src, size_t n); +void *rust_bzip2_wasm_shim_memset(void *dest, int c, size_t n); inline void *memcpy(void *restrict dest, const void *restrict src, size_t n) { - return rust_zstd_wasm_shim_memcpy(dest, src, n); + return rust_bzip2_wasm_shim_memcpy(dest, src, n); } inline void *memmove(void *dest, const void *src, size_t n) { - return rust_zstd_wasm_shim_memmove(dest, src, n); + return rust_bzip2_wasm_shim_memmove(dest, src, n); } inline void *memset(void *dest, int c, size_t n) { - return rust_zstd_wasm_shim_memset(dest, c, n); + return rust_bzip2_wasm_shim_memset(dest, c, n); } #endif // _STRING_H diff --git a/bzip2-sys/wasm_shim.rs b/bzip2-sys/wasm_shim.rs index 8bfd7baf..0a2fae7f 100644 --- a/bzip2-sys/wasm_shim.rs +++ b/bzip2-sys/wasm_shim.rs @@ -2,7 +2,7 @@ use std::alloc::{alloc, dealloc, Layout}; use std::os::raw::{c_int, c_void}; #[no_mangle] -pub extern "C" fn rust_zstd_wasm_shim_malloc(size: usize) -> *mut c_void { +pub extern "C" fn rust_bzip2_wasm_shim_malloc(size: usize) -> *mut c_void { unsafe { let layout = Layout::from_size_align_unchecked(size, 1); alloc(layout).cast() @@ -10,7 +10,7 @@ pub extern "C" fn rust_zstd_wasm_shim_malloc(size: usize) -> *mut c_void { } #[no_mangle] -pub extern "C" fn rust_zstd_wasm_shim_calloc(nmemb: usize, size: usize) -> *mut c_void { +pub extern "C" fn rust_bzip2_wasm_shim_calloc(nmemb: usize, size: usize) -> *mut c_void { unsafe { let layout = Layout::from_size_align_unchecked(size * nmemb, 1); alloc(layout).cast() @@ -18,14 +18,14 @@ pub extern "C" fn rust_zstd_wasm_shim_calloc(nmemb: usize, size: usize) -> *mut } #[no_mangle] -pub unsafe extern "C" fn rust_zstd_wasm_shim_free(ptr: *mut c_void) { +pub unsafe extern "C" fn rust_bzip2_wasm_shim_free(ptr: *mut c_void) { // layout is not actually used let layout = Layout::from_size_align_unchecked(1, 1); dealloc(ptr.cast(), layout); } #[no_mangle] -pub unsafe extern "C" fn rust_zstd_wasm_shim_memcpy( +pub unsafe extern "C" fn rust_bzip2_wasm_shim_memcpy( dest: *mut c_void, src: *const c_void, n: usize, @@ -35,7 +35,7 @@ pub unsafe extern "C" fn rust_zstd_wasm_shim_memcpy( } #[no_mangle] -pub unsafe extern "C" fn rust_zstd_wasm_shim_memmove( +pub unsafe extern "C" fn rust_bzip2_wasm_shim_memmove( dest: *mut c_void, src: *const c_void, n: usize, @@ -45,7 +45,7 @@ pub unsafe extern "C" fn rust_zstd_wasm_shim_memmove( } #[no_mangle] -pub unsafe extern "C" fn rust_zstd_wasm_shim_memset( +pub unsafe extern "C" fn rust_bzip2_wasm_shim_memset( dest: *mut c_void, c: c_int, n: usize, From e88c2cb9d45ef1e2c34e2d08ea310fdb66735421 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Wed, 13 Sep 2023 19:13:04 +0200 Subject: [PATCH 4/7] improve WASM feature --- bzip2-sys/Cargo.toml | 2 - bzip2-sys/build.rs | 12 ++--- bzip2-sys/bzlib.h | 15 ------ bzip2-sys/examples/it_work.rs | 4 -- bzip2-sys/lib.rs | 10 ++-- bzip2-sys/wasm_shim.rs | 55 --------------------- bzip2-sys/wasm_shim/README.md | 13 +++++ bzip2-sys/wasm_shim/mod.rs | 55 +++++++++++++++++++++ bzip2-sys/{wasm-shim => wasm_shim}/stdlib.h | 0 bzip2-sys/{wasm-shim => wasm_shim}/string.h | 0 10 files changed, 78 insertions(+), 88 deletions(-) delete mode 100644 bzip2-sys/bzlib.h delete mode 100644 bzip2-sys/wasm_shim.rs create mode 100644 bzip2-sys/wasm_shim/README.md create mode 100644 bzip2-sys/wasm_shim/mod.rs rename bzip2-sys/{wasm-shim => wasm_shim}/stdlib.h (100%) rename bzip2-sys/{wasm-shim => wasm_shim}/string.h (100%) diff --git a/bzip2-sys/Cargo.toml b/bzip2-sys/Cargo.toml index 4b3973e6..bc2318f6 100644 --- a/bzip2-sys/Cargo.toml +++ b/bzip2-sys/Cargo.toml @@ -28,5 +28,3 @@ cc = "1.0" [features] # Enable this feature if you want to have a statically linked bzip2 static = [] -std = [] # Use std types instead of libc in bindgen - diff --git a/bzip2-sys/build.rs b/bzip2-sys/build.rs index 55ac5b39..e8fa89da 100644 --- a/bzip2-sys/build.rs +++ b/bzip2-sys/build.rs @@ -27,16 +27,14 @@ fn main() { // Note that Emscripten already provides its own C standard library so // wasm32-unknown-emscripten should not be included here. // See: https://github.com/gyscos/zstd-rs/pull/209 - let need_wasm_shim = env::var("TARGET").map_or(false, |target| { - target == "wasm32-unknown-unknown" || target == "wasm32-wasi" - }); + let need_wasm_shim = + env::var("TARGET").map_or(false, |target| target == "wasm32-unknown-unknown"); if need_wasm_shim { - cargo_print(&"rerun-if-changed=wasm-shim/stdlib.h"); - cargo_print(&"rerun-if-changed=wasm-shim/string.h"); + cargo_print(&"rerun-if-changed=wasm_shim/stdlib.h"); + cargo_print(&"rerun-if-changed=wasm_shim/string.h"); - cfg.include("wasm-shim/"); - cfg.define("XXH_STATIC_ASSERT", Some("0")); + cfg.include("wasm_shim/"); cfg.opt_level(3); } let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); diff --git a/bzip2-sys/bzlib.h b/bzip2-sys/bzlib.h deleted file mode 100644 index f91ae837..00000000 --- a/bzip2-sys/bzlib.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifdef PKG_CONFIG - -/* Just use installed headers */ -#include - -#else // #ifdef PKG_CONFIG - -#include "bzip2-1.0.8/bzlib.h" - -#endif // #ifdef PKG_CONFIG - - -/* This file is used to generate bindings for both headers. - * Check update_bindings.sh to see how to use it. - * Or use the `bindgen` feature, which will create the bindings automatically. */ diff --git a/bzip2-sys/examples/it_work.rs b/bzip2-sys/examples/it_work.rs index af92f004..86ac6992 100644 --- a/bzip2-sys/examples/it_work.rs +++ b/bzip2-sys/examples/it_work.rs @@ -1,9 +1,5 @@ -#[cfg(feature = "std")] use std::os::raw::{c_char, c_int, c_uint}; -#[cfg(not(feature = "std"))] -use libc::{c_char, c_int, c_uint}; - #[no_mangle] pub extern "C" fn test_decompress() -> bool { let uncompressed_bytes = include_bytes!("../bzip2-1.0.8/sample1.ref"); diff --git a/bzip2-sys/lib.rs b/bzip2-sys/lib.rs index 84f7b7b9..43569da8 100644 --- a/bzip2-sys/lib.rs +++ b/bzip2-sys/lib.rs @@ -2,15 +2,15 @@ extern crate libc; -#[cfg(target_arch = "wasm32")] +#[cfg(all( + target_arch = "wasm32", + target_vendor = "unknown", + target_os = "unknown" +))] mod wasm_shim; -#[cfg(feature = "std")] use std::os::raw::{c_char, c_int, c_uint, c_void}; -#[cfg(not(feature = "std"))] -use libc::{c_char, c_int, c_uint, c_void}; - pub const BZ_RUN: c_int = 0; pub const BZ_FLUSH: c_int = 1; pub const BZ_FINISH: c_int = 2; diff --git a/bzip2-sys/wasm_shim.rs b/bzip2-sys/wasm_shim.rs deleted file mode 100644 index 0a2fae7f..00000000 --- a/bzip2-sys/wasm_shim.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::alloc::{alloc, dealloc, Layout}; -use std::os::raw::{c_int, c_void}; - -#[no_mangle] -pub extern "C" fn rust_bzip2_wasm_shim_malloc(size: usize) -> *mut c_void { - unsafe { - let layout = Layout::from_size_align_unchecked(size, 1); - alloc(layout).cast() - } -} - -#[no_mangle] -pub extern "C" fn rust_bzip2_wasm_shim_calloc(nmemb: usize, size: usize) -> *mut c_void { - unsafe { - let layout = Layout::from_size_align_unchecked(size * nmemb, 1); - alloc(layout).cast() - } -} - -#[no_mangle] -pub unsafe extern "C" fn rust_bzip2_wasm_shim_free(ptr: *mut c_void) { - // layout is not actually used - let layout = Layout::from_size_align_unchecked(1, 1); - dealloc(ptr.cast(), layout); -} - -#[no_mangle] -pub unsafe extern "C" fn rust_bzip2_wasm_shim_memcpy( - dest: *mut c_void, - src: *const c_void, - n: usize, -) -> *mut c_void { - std::ptr::copy_nonoverlapping(src as *const u8, dest as *mut u8, n); - dest -} - -#[no_mangle] -pub unsafe extern "C" fn rust_bzip2_wasm_shim_memmove( - dest: *mut c_void, - src: *const c_void, - n: usize, -) -> *mut c_void { - std::ptr::copy(src as *const u8, dest as *mut u8, n); - dest -} - -#[no_mangle] -pub unsafe extern "C" fn rust_bzip2_wasm_shim_memset( - dest: *mut c_void, - c: c_int, - n: usize, -) -> *mut c_void { - std::ptr::write_bytes(dest as *mut u8, c as u8, n); - dest -} diff --git a/bzip2-sys/wasm_shim/README.md b/bzip2-sys/wasm_shim/README.md new file mode 100644 index 00000000..1156da55 --- /dev/null +++ b/bzip2-sys/wasm_shim/README.md @@ -0,0 +1,13 @@ +# WASM shims + +This directory contains some WASM shims for C-functions used by bzip2 that are not available otherwise for the `wasm32-unknown-unknow` target. +Specifically, these are: + +- `malloc` +- `calloc` +- `free` +- `memset` +- `memcpy` +- `memmove` + +The shims are implemented in Rust and exposed as C functions that the bzip2-sys crate can then use / link against. \ No newline at end of file diff --git a/bzip2-sys/wasm_shim/mod.rs b/bzip2-sys/wasm_shim/mod.rs new file mode 100644 index 00000000..048f1e93 --- /dev/null +++ b/bzip2-sys/wasm_shim/mod.rs @@ -0,0 +1,55 @@ +use std::alloc::{alloc, alloc_zeroed, dealloc, Layout}; + +const ALIGNMENT: usize = 16; + +#[no_mangle] +pub extern "C" fn rust_bzip2_wasm_shim_malloc(size: usize) -> *mut u8 { + unsafe { + let layout = Layout::from_size_align_unchecked(size, ALIGNMENT); + alloc(layout) + } +} + +#[no_mangle] +pub extern "C" fn rust_bzip2_wasm_shim_calloc(nmemb: usize, size: usize) -> *mut u8 { + let total_size = nmemb * size; + unsafe { + let layout = Layout::from_size_align_unchecked(total_size, ALIGNMENT); + alloc_zeroed(layout) + } +} + +#[no_mangle] +pub unsafe extern "C" fn rust_bzip2_wasm_shim_free(ptr: *mut u8) { + // layout is not actually used + unsafe { + let layout = Layout::from_size_align_unchecked(1, ALIGNMENT); + dealloc(ptr.cast(), layout); + } +} + +#[no_mangle] +pub unsafe extern "C" fn rust_bzip2_wasm_shim_memcpy( + dest: *mut u8, + src: *const u8, + n: usize, +) -> *mut u8 { + std::ptr::copy_nonoverlapping(src, dest, n); + dest +} + +#[no_mangle] +pub unsafe extern "C" fn rust_bzip2_wasm_shim_memmove( + dest: *mut u8, + src: *const u8, + n: usize, +) -> *mut u8 { + std::ptr::copy(src, dest, n); + dest +} + +#[no_mangle] +pub unsafe extern "C" fn rust_bzip2_wasm_shim_memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 { + std::ptr::write_bytes(dest, c as u8, n); + dest +} diff --git a/bzip2-sys/wasm-shim/stdlib.h b/bzip2-sys/wasm_shim/stdlib.h similarity index 100% rename from bzip2-sys/wasm-shim/stdlib.h rename to bzip2-sys/wasm_shim/stdlib.h diff --git a/bzip2-sys/wasm-shim/string.h b/bzip2-sys/wasm_shim/string.h similarity index 100% rename from bzip2-sys/wasm-shim/string.h rename to bzip2-sys/wasm_shim/string.h From 74c78a494b5ff359e441cddebbfd86a3f06b5134 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Wed, 13 Sep 2023 19:14:07 +0200 Subject: [PATCH 5/7] remove more libc --- bzip2-sys/Cargo.toml | 3 --- bzip2-sys/lib.rs | 2 -- 2 files changed, 5 deletions(-) diff --git a/bzip2-sys/Cargo.toml b/bzip2-sys/Cargo.toml index bc2318f6..5eab5d11 100644 --- a/bzip2-sys/Cargo.toml +++ b/bzip2-sys/Cargo.toml @@ -18,9 +18,6 @@ categories = ["external-ffi-bindings"] name = "bzip2_sys" path = "lib.rs" -[dependencies] -libc = "0.2" - [build-dependencies] pkg-config = "0.3.9" cc = "1.0" diff --git a/bzip2-sys/lib.rs b/bzip2-sys/lib.rs index 43569da8..93749c29 100644 --- a/bzip2-sys/lib.rs +++ b/bzip2-sys/lib.rs @@ -1,7 +1,5 @@ #![doc(html_root_url = "https://docs.rs/bzip2-sys/0.1")] -extern crate libc; - #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", From 635bae02fb13aa2fdcb7a5be6d1544872f5322cc Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 1 Mar 2024 10:26:28 +0100 Subject: [PATCH 6/7] improve the implementation --- bzip2-sys/wasm_shim/README.md | 2 +- bzip2-sys/wasm_shim/mod.rs | 50 ++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/bzip2-sys/wasm_shim/README.md b/bzip2-sys/wasm_shim/README.md index 1156da55..45bad3b8 100644 --- a/bzip2-sys/wasm_shim/README.md +++ b/bzip2-sys/wasm_shim/README.md @@ -10,4 +10,4 @@ Specifically, these are: - `memcpy` - `memmove` -The shims are implemented in Rust and exposed as C functions that the bzip2-sys crate can then use / link against. \ No newline at end of file +The shims are implemented in Rust and exposed as C functions that the bzip2-sys crate can then use / link against. diff --git a/bzip2-sys/wasm_shim/mod.rs b/bzip2-sys/wasm_shim/mod.rs index 048f1e93..cfcb53a0 100644 --- a/bzip2-sys/wasm_shim/mod.rs +++ b/bzip2-sys/wasm_shim/mod.rs @@ -1,12 +1,35 @@ use std::alloc::{alloc, alloc_zeroed, dealloc, Layout}; +use std::mem; +use std::ptr; -const ALIGNMENT: usize = 16; +// Define a struct to hold the size before the allocated memory +#[repr(C)] +struct AllocationHeader { + size: usize, +} + +const HEADER_SIZE: usize = mem::size_of::(); +const ALIGNMENT: usize = 2 * mem::size_of::(); + +// Helper function to create a layout that includes the header +fn layout_with_header(size: usize) -> Layout { + let adjusted_size = HEADER_SIZE + size; + Layout::from_size_align(adjusted_size, ALIGNMENT).expect("Layout creation failed") +} #[no_mangle] pub extern "C" fn rust_bzip2_wasm_shim_malloc(size: usize) -> *mut u8 { unsafe { - let layout = Layout::from_size_align_unchecked(size, ALIGNMENT); - alloc(layout) + let layout = layout_with_header(size); + let ptr = alloc(layout) as *mut AllocationHeader; + if !ptr.is_null() { + // Store the original size in the header + (*ptr).size = size; + // Return a pointer to the memory after the header + ptr.add(1) as *mut u8 + } else { + ptr::null_mut() + } } } @@ -14,17 +37,24 @@ pub extern "C" fn rust_bzip2_wasm_shim_malloc(size: usize) -> *mut u8 { pub extern "C" fn rust_bzip2_wasm_shim_calloc(nmemb: usize, size: usize) -> *mut u8 { let total_size = nmemb * size; unsafe { - let layout = Layout::from_size_align_unchecked(total_size, ALIGNMENT); - alloc_zeroed(layout) + let layout = layout_with_header(total_size); + let ptr = alloc_zeroed(layout) as *mut AllocationHeader; + if !ptr.is_null() { + (*ptr).size = total_size; + ptr.add(1) as *mut u8 + } else { + ptr::null_mut() + } } } #[no_mangle] pub unsafe extern "C" fn rust_bzip2_wasm_shim_free(ptr: *mut u8) { - // layout is not actually used - unsafe { - let layout = Layout::from_size_align_unchecked(1, ALIGNMENT); - dealloc(ptr.cast(), layout); + if !ptr.is_null() { + let ptr = (ptr as *mut AllocationHeader).sub(1); // Move back to the header + let size = (*ptr).size; + let layout = layout_with_header(size); + dealloc(ptr as *mut u8, layout); } } @@ -52,4 +82,4 @@ pub unsafe extern "C" fn rust_bzip2_wasm_shim_memmove( pub unsafe extern "C" fn rust_bzip2_wasm_shim_memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 { std::ptr::write_bytes(dest, c as u8, n); dest -} +} \ No newline at end of file From 81763c1dc18695c68936bd963eeccd028da1df08 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 1 Mar 2024 10:31:17 +0100 Subject: [PATCH 7/7] fmt --- bzip2-sys/wasm_shim/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bzip2-sys/wasm_shim/mod.rs b/bzip2-sys/wasm_shim/mod.rs index cfcb53a0..c3c0fddd 100644 --- a/bzip2-sys/wasm_shim/mod.rs +++ b/bzip2-sys/wasm_shim/mod.rs @@ -26,7 +26,7 @@ pub extern "C" fn rust_bzip2_wasm_shim_malloc(size: usize) -> *mut u8 { // Store the original size in the header (*ptr).size = size; // Return a pointer to the memory after the header - ptr.add(1) as *mut u8 + ptr.add(1) as *mut u8 } else { ptr::null_mut() } @@ -82,4 +82,4 @@ pub unsafe extern "C" fn rust_bzip2_wasm_shim_memmove( pub unsafe extern "C" fn rust_bzip2_wasm_shim_memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 { std::ptr::write_bytes(dest, c as u8, n); dest -} \ No newline at end of file +}