wizer 10.0.0

The WebAssembly Pre-Initializer
Documentation
use anyhow::{anyhow, Context, Result};
use std::rc::Rc;
use wasmtime_wasi::WasiCtxBuilder;
use wat::parse_str as wat_to_wasm;
use wizer::Wizer;

fn get_wizer() -> Wizer {
    let mut wizer = Wizer::new();
    wizer
        .make_linker(Some(Rc::new(|e: &wasmtime::Engine| {
            let mut linker = wasmtime::Linker::new(e);
            linker.func_wrap("foo", "bar", |x: i32| x + 1)?;
            Ok(linker)
        })))
        .unwrap();
    wizer
}

fn run_wasm(args: &[wasmtime::Val], expected: i32, wasm: &[u8]) -> Result<()> {
    let _ = env_logger::try_init();

    let wasm = get_wizer().run(&wasm)?;
    log::debug!(
        "=== Wizened Wasm ==========================================================\n\
       {}\n\
       ===========================================================================",
        wasmprinter::print_bytes(&wasm).unwrap()
    );
    if log::log_enabled!(log::Level::Debug) {
        std::fs::write("test.wasm", &wasm).unwrap();
    }

    let mut config = wasmtime::Config::new();
    wasmtime::Cache::from_file(None)
        .map(|cache| config.cache(Some(cache)))
        .unwrap();
    config.wasm_multi_memory(true);
    config.wasm_multi_value(true);

    let engine = wasmtime::Engine::new(&config)?;
    let wasi_ctx = WasiCtxBuilder::new().build_p1();
    let mut store = wasmtime::Store::new(&engine, wasi_ctx);
    let module =
        wasmtime::Module::new(store.engine(), wasm).context("Wasm test case failed to compile")?;

    let mut linker = wasmtime::Linker::new(&engine);
    linker.func_wrap("foo", "bar", |_: i32| -> Result<i32> {
        Err(anyhow!("shouldn't be called"))
    })?;

    let instance = linker.instantiate(&mut store, &module)?;

    let run = instance
        .get_func(&mut store, "run")
        .ok_or_else(|| anyhow::anyhow!("the test Wasm module does not export a `run` function"))?;

    let mut actual = vec![wasmtime::Val::I32(0)];
    run.call(&mut store, args, &mut actual)?;
    anyhow::ensure!(actual.len() == 1, "expected one result");
    let actual = match actual[0] {
        wasmtime::Val::I32(x) => x,
        _ => anyhow::bail!("expected an i32 result"),
    };
    anyhow::ensure!(
        expected == actual,
        "expected `{}`, found `{}`",
        expected,
        actual,
    );

    Ok(())
}

fn run_wat(args: &[wasmtime::Val], expected: i32, wat: &str) -> Result<()> {
    let _ = env_logger::try_init();
    let wasm = wat_to_wasm(wat)?;
    run_wasm(args, expected, &wasm)
}

#[test]
fn custom_linker() -> Result<()> {
    run_wat(
        &[],
        1,
        r#"
(module
  (type (func (param i32) (result i32)))
  (import "foo" "bar" (func (type 0)))
  (global $g (mut i32) (i32.const 0))
  (func (export "wizer.initialize")
    global.get $g
    call 0
    global.set $g
  )
  (func (export "run") (result i32)
    (global.get $g)
  )
)"#,
    )
}

#[test]
#[should_panic]
fn linker_and_wasi() {
    Wizer::new()
        .make_linker(Some(Rc::new(|e: &wasmtime::Engine| {
            Ok(wasmtime::Linker::new(e))
        })))
        .unwrap()
        .allow_wasi(true)
        .unwrap();
}

#[test]
#[should_panic]
fn wasi_and_linker() {
    Wizer::new()
        .allow_wasi(true)
        .unwrap()
        .make_linker(Some(Rc::new(|e: &wasmtime::Engine| {
            Ok(wasmtime::Linker::new(e))
        })))
        .unwrap();
}