Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ zig-cache/
# Python
__pycache__/

# Rust
target/
Cargo.lock

# Editor
*.swp
*~
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ C example using `libzwasm`: load a module, invoke an export, read the result.

Python ctypes example: same workflow as C, no compiled bindings needed.

### Rust examples (`examples/rust/`)

Rust FFI example: same workflow as C, using `extern "C"` bindings.

## Build

Requires Zig 0.15.2.
Expand Down
7 changes: 7 additions & 0 deletions examples/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "rust-example"
version = "0.1.0"
edition = "2024"
build = "build.rs"

[dependencies]
16 changes: 16 additions & 0 deletions examples/rust/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::{env, path::PathBuf};

fn main() {
let manifest = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let lib_dir = manifest
.join("..")
.join("..")
.join("zig-out")
.join("lib")
.canonicalize()
.expect("zig-out/lib not found — run `zig build lib` first");

println!("cargo:rustc-link-search=native={}", lib_dir.display());
println!("cargo:rustc-link-lib=zwasm");
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir.display());
}
68 changes: 68 additions & 0 deletions examples/rust/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//! main.rs — Minimal example using the zwasm C API via FFI
//!
//! Demonstrates: load module, invoke exported function, read result.
//!
//! Build: zig build lib && cargo build
//! Run: cargo run

#[repr(C)]
struct zwasm_module_t {
_private: [u8; 0],
}

#[link(name = "zwasm")]
unsafe extern "C" {
fn zwasm_module_new(wasm_ptr: *const u8, len: usize) -> *mut zwasm_module_t;
fn zwasm_module_invoke(
module: *mut zwasm_module_t,
name: *const std::ffi::c_char,
args: *mut u64,
nargs: u32,
results: *mut u64,
nresults: u32,
) -> bool;
fn zwasm_module_delete(module: *mut zwasm_module_t);
fn zwasm_last_error_message() -> *const std::ffi::c_char;
}

/* Wasm module: export "f" () -> i32 { return 42 } */
const WASM: &[u8] = &[
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7f, 0x03,
0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x06, 0x01, 0x04, 0x00, 0x41,
0x2a, 0x0b,
];

fn main() {
unsafe {
let module = zwasm_module_new(WASM.as_ptr(), WASM.len());

if module.is_null() {
let err_msg = zwasm_last_error_message();
let c_str = std::ffi::CStr::from_ptr(err_msg);
eprintln!("Failed to create module: {}", c_str.to_str().unwrap());
return;
}

let name = std::ffi::CString::new("f").unwrap();
let mut results = [0u64; 1];
let ok = zwasm_module_invoke(
module,
name.as_ptr(),
std::ptr::null_mut(),
0,
results.as_mut_ptr(),
results.len() as u32,
);

if !ok {
let err_msg = zwasm_last_error_message();
let c_str = std::ffi::CStr::from_ptr(err_msg);
eprintln!("Invoke error: {}", c_str.to_str().unwrap());
zwasm_module_delete(module);
return;
}

println!("f() = {}", results[0]);
zwasm_module_delete(module);
}
}