Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fizzyx

Rust bindings for the Fizzy WebAssembly interpreter.

Fizzy is a small, fast, deterministic interpreter implementing the WebAssembly 1.0 (MVP) specification. fizzyx wraps Fizzy's C API in a safe, ergonomic Rust interface inspired by wasmi and wasmtime.

Crates

Crate Description
fizzyx Safe, high-level API (Engine, Module, Linker, Instance, Func, …).
fizzyx-sys Low-level unsafe FFI bindings generated with bindgen.

Most users only need fizzyx.

Quick start

use fizzyx::{Engine, Linker, Module, Val};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let wat = r#"(module (func (export "add") (param i32 i32) (result i32)
        local.get 0
        local.get 1
        i32.add))"#;
    let wasm = wat::parse_str(wat)?;

    let engine = Engine::default();
    let module = Module::new(&wasm)?;
    let linker = Linker::new(&engine);
    let mut instance = linker.instantiate(&module)?;

    let add = instance.get_func("add").expect("missing export");
    let mut results = [Val::I32(0)];
    add.call(&mut instance, &[Val::I32(1), Val::I32(2)], &mut results)?;
    assert_eq!(results[0], Val::I32(3));
    Ok(())
}

Host functions are defined on the Linker before instantiation:

use fizzyx::{FuncType, Val, ValType};

linker.func_new(
    "env",
    "mul",
    FuncType::new([ValType::I32, ValType::I32], [ValType::I32]),
    |params, results| {
        let a = params[0].i32().unwrap();
        let b = params[1].i32().unwrap();
        results[0] = Val::I32(a * b);
    },
)?;

Differences from wasmtime / wasmi

The API follows Fizzy's own model instead of forcing an exact match:

  • At most one result. Fizzy targets WebAssembly 1.0, so functions return zero or one value.
  • No Store. Fizzy instances are self-contained — they own their memory and globals — so there is no separate store. Methods that mutate an instance take &mut Instance directly.
  • Instantiate-time imports. Imports are resolved by module::name when a module is instantiated through a Linker. Only function imports are currently supported; instantiating a module that imports a memory, table, or global fails.
  • No fuel/metering. Fizzy's metered execution context is not yet exposed.

Building

fizzyx-sys builds Fizzy from source, vendored as a git submodule. After cloning:

git submodule update --init --recursive
cargo build

Requirements:

  • A C++17 toolchain and CMake (≥ 3.15) to build Fizzy.
  • libclang for bindgen.

Fizzy stores its byte buffers as std::basic_string<uint8_t>. Modern libc++ (≥ 19, e.g. the Xcode 16 SDK) no longer provides std::char_traits<unsigned char>, so the build script force-includes a small shim (crates/fizzyx-sys/shim/char_traits_shim.hpp) that supplies it. The shim is a no-op on libstdc++.

Vendored sources and updating Fizzy

Fizzy's repository root ships its own Cargo.toml, which makes Cargo treat the submodule as a foreign package and exclude it from published tarballs. So fizzyx-sys builds and publishes from a committed, Cargo.toml-free mirror of the sources it needs at crates/fizzyx-sys/fizzy-vendored/. build.rs regenerates that mirror from the submodule on every build, so you never edit it by hand.

To update Fizzy:

git -C crates/fizzyx-sys/fizzy checkout <new-commit>   # bump the submodule
cargo build -p fizzyx-sys                              # regenerates fizzy-vendored/
git add crates/fizzyx-sys/fizzy crates/fizzyx-sys/fizzy-vendored
git commit -m "update Fizzy"

CI fails if fizzy-vendored/ is out of sync with the submodule.

License

Licensed under either of

at your option. The vendored Fizzy sources are licensed under Apache-2.0.

About

Rust bindings for the Fizzy Wasm interpreter.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages