diff --git a/Cargo.lock b/Cargo.lock index 3670a31..806c738 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -865,11 +865,20 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wamr-macros" +version = "1.0.0" +dependencies = [ + "quote", + "syn 2.0.48", +] + [[package]] name = "wamr-rust-sdk" version = "1.0.0" dependencies = [ "esp-idf-sys", + "wamr-macros", "wamr-sys", ] diff --git a/Cargo.toml b/Cargo.toml index 6c2aa3b..1d54584 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,13 +2,13 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception [workspace] -members = ["crates/wamr-sys"] +members = [ + "crates/wamr-macros", + "crates/wamr-sys", +] exclude = [ - "examples/wasi-hello", - "resources/test/gcd", - "resources/test/add-extra", - ".devcontainer", - ".github", + "examples/modules", + "tests/fixtures", ] resolver = "2" @@ -29,6 +29,7 @@ categories = ["api-bindings", "wasm"] keywords = ["api-bindings", "wasm", "webassembly"] [dependencies] +wamr-macros = { path = "crates/wamr-macros", version = "1.0.0", optional = true } wamr-sys = { path = "crates/wamr-sys", version = "1.0.0" } [target.'cfg( target_os = "espidf" )'.dependencies] @@ -39,6 +40,8 @@ bindings_header = "./crates/wamr-sys/wasm-micro-runtime/core/iwasm/include/wasm_ component_dirs = ["./crates/wamr-sys/wasm-micro-runtime/build-scripts/esp-idf"] [features] +default = ["macros"] +macros = ["wamr-macros"] custom-section = ["wamr-sys/custom-section"] dump-call-stack = ["wamr-sys/dump-call-stack"] esp-idf = ["esp-idf-sys", "wamr-sys/esp-idf"] diff --git a/README.md b/README.md index 395c613..108a470 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ This crate has similar concepts to the #### WAMR private concepts - *loading linking* instead of *instantiation linking*. *instantiation linking* is -used in Wasm JS API and Wasm C API. It means that every instance has its own, maybe -variant, imports. But *loading linking* means that all instances share the same *imports*. + used in Wasm JS API and Wasm C API. It means that every instance has its own, maybe + variant, imports. But *loading linking* means that all instances share the same *imports*. - *RuntimeArg*. Control runtime behavior. - *running mode*. @@ -50,7 +50,22 @@ variant, imports. But *loading linking* means that all instances share the same ### Examples -#### Example: to run a wasm32-wasi .wasm +Under the [`examples`](examples) contains a number of examples showcasing various +capabilities of the `wamr-rust-sdk` crate. + +All examples can be executed with: + +```sh +cargo run --example $name +``` + +A good starting point for the examples would be [`examples/basic`](examples/basic.rs). + +If you've got an example you'd like to see here, please feel free to open an +issue. Otherwise if you've got an example you'd like to add, please feel free +to make a PR! + +#### Quick Start: to run a wasm32-wasi .wasm *wasm32-wasi* is a most common target for Wasm. It means that the .wasm is compiled with `cargo build --target wasm32-wasi` or `wasi-sdk/bin/clang --target wasm32-wasi`. @@ -65,13 +80,12 @@ use wamr_rust_sdk::{ runtime::Runtime, module::Module, instance::Instance, function::Function, value::WasmValue, RuntimeError }; -use std::path::PathBuf; fn main() -> Result<(), RuntimeError> { let runtime = Runtime::new()?; - let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("resources/test"); + let mut d = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("tests/fixtures"); d.push("gcd_wasm32_wasi.wasm"); let module = Module::from_file(&runtime, d.as_path())?; @@ -88,7 +102,7 @@ fn main() -> Result<(), RuntimeError> { } ``` -#### Example: more configuration for runtime. +#### Quick Start: more configuration for runtime. With more configuration, runtime is capable to run .wasm with variant features, like - Wasm without WASI requirement. Usually, it means that the .wasm is compiled with `-nostdlib` @@ -104,25 +118,25 @@ The rust code to call the *add* function is like this: ```rust use wamr_rust_sdk::{ - runtime::Runtime, module::Module, instance::Instance, function::Function, - value::WasmValue, RuntimeError + function::Function, generate_host_function, instance::Instance, module::Module, + runtime::Runtime, value::WasmValue, RuntimeError }; -use std::path::PathBuf; -use std::ffi::c_void; -extern "C" fn extra() -> i32 { +#[generate_host_function] +fn extra() -> i32 { 100 } fn main() -> Result<(), RuntimeError> { let runtime = Runtime::builder() .use_system_allocator() - .register_host_function("extra", extra as *mut c_void) + .register_host_function(extra) .build()?; - let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("resources/test"); + let mut d = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("tests/fixtures"); d.push("add_extra_wasm32_wasi.wasm"); + let module = Module::from_file(&runtime, d.as_path())?; let instance = Instance::new(&runtime, &module, 1024 * 64)?; @@ -136,4 +150,3 @@ fn main() -> Result<(), RuntimeError> { Ok(()) } ``` - diff --git a/crates/wamr-macros/Cargo.toml b/crates/wamr-macros/Cargo.toml new file mode 100644 index 0000000..a0d229e --- /dev/null +++ b/crates/wamr-macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "wamr-macros" +version = "1.0.0" +edition = "2021" +license = "Apache-2.0 WITH LLVM-exception" +authors = ["The WAMR Project Developers"] + +[lib] +proc-macro = true + +[dependencies] +quote = "1" +syn = { version = "2", features = ["full"] } diff --git a/crates/wamr-macros/src/lib.rs b/crates/wamr-macros/src/lib.rs new file mode 100644 index 0000000..846503e --- /dev/null +++ b/crates/wamr-macros/src/lib.rs @@ -0,0 +1,120 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::quote; +use syn::{meta, parse_macro_input, FnArg, ItemFn, LitStr, ReturnType, Type}; + +#[proc_macro_attribute] +pub fn generate_host_function(args: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as ItemFn); + + let mut name_override: Option = None; + let mut signature_override: Option = None; + + let args_parser = meta::parser(|meta| { + if meta.path.is_ident("name") { + name_override = Some(meta.value()?.parse()?); + } else if meta.path.is_ident("signature") { + signature_override = Some(meta.value()?.parse()?); + } else { + return Err(meta.error("unsupported generate host function property.")); + } + Ok(()) + }); + + parse_macro_input!(args with args_parser); + + let function_ident = &input.sig.ident; + let function_vis = &input.vis; + let function_inputs = &input.sig.inputs; + let function_output = &input.sig.output; + let function_block = &input.block; + + let function_name = name_override + .map(|n| n.value()) + .unwrap_or_else(|| function_ident.to_string()); + + let signature = signature_override.map(|s| s.value()).unwrap_or_else(|| { + let mut param_signature = String::new(); + let mut buffer_flag = false; + + for arg in function_inputs.iter() { + if let FnArg::Typed(typed) = arg { + let sig_char = get_signature_for_type(&typed.ty) + .unwrap_or_else(|| panic!("Unsupported parameter type.")); + + if sig_char == '~' && !buffer_flag { + panic!("`~` must follow `*` (buffer address)."); + } + + buffer_flag = sig_char == '*'; + param_signature.push(sig_char); + } + } + + let return_signature = match function_output { + ReturnType::Default => String::new(), + ReturnType::Type(_, ret_type) => get_signature_for_type(ret_type) + .unwrap_or_else(|| panic!("Unsupported return type.")) + .to_string(), + }; + + format!("({}){}", param_signature, return_signature) + }); + + let c_function_ident = syn::Ident::new(&format!("{}_c", function_ident), function_ident.span()); + + let expanded = quote! { + #function_vis extern "C" fn #c_function_ident(exec_env: wamr_rust_sdk::sys::wasm_exec_env_t, #function_inputs) #function_output #function_block + + #function_vis fn #function_ident() -> wamr_rust_sdk::host_function::HostFunction { + wamr_rust_sdk::host_function::HostFunction::new( + #function_name, + #c_function_ident as *mut core::ffi::c_void, + #signature + ) + } + }; + + TokenStream::from(expanded) +} + +fn get_signature_for_type(ty: &Type) -> Option { + match ty { + Type::Path(type_path) => { + let type_name = type_path.path.segments.last()?.ident.to_string(); + match type_name.as_str() { + "i32" | "u32" => Some('i'), + "i64" | "u64" => Some('I'), + "f32" => Some('f'), + "f64" => Some('F'), + "usize" => Some('i'), + _ => None, + } + } + Type::Reference(type_ref) => match &*type_ref.elem { + Type::Path(type_path) => { + let type_name = type_path.path.segments.last()?.ident.to_string(); + if type_name == "str" { + Some('$') + } else { + None + } + } + _ => None, + }, + Type::Ptr(type_ptr) => { + if let Type::Path(type_path) = &*type_ptr.elem { + let type_name = type_path.path.segments.last()?.ident.to_string(); + if type_name == "u8" { + Some('*') + } else { + None + } + } else { + None + } + } + _ => None, + } +} diff --git a/examples/basic.rs b/examples/basic.rs new file mode 100644 index 0000000..b71799c --- /dev/null +++ b/examples/basic.rs @@ -0,0 +1,100 @@ +use std::path::PathBuf; +use std::time::{SystemTime, UNIX_EPOCH}; + +use wamr_rust_sdk::{ + function::Function, generate_host_function, instance::Instance, module::Module, + runtime::Runtime, value::WasmValue, wasi_context::WasiCtxBuilder, RuntimeError, + sys::wasm_runtime_call_indirect, +}; + +#[generate_host_function] +fn now() -> i64 { + (SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Clock may have gone backwards") + .as_nanos() % 1_000_000) as i64 +} + +#[generate_host_function] +fn mystery(n: f32, func1: u32, func2: u32) -> f32 { + let mut argv: Vec = Vec::with_capacity(2); + + let mut data_buffer: Vec = WasmValue::F32(n).encode(); + argv.append(&mut data_buffer); + + let (mut n1, mut n2): (f32, f32) = (0.0, 0.0); + + let func1_result = unsafe { wasm_runtime_call_indirect(exec_env, func1, 1, argv.as_mut_ptr()) }; + + if !func1_result { + println!("call func1 failed"); + return 0.0; + } + + if let WasmValue::F32(f1) = WasmValue::decode_to_f32(argv.clone()) { + assert_eq!(f1, n * 5.0); + n1 = f1; + } else { + println!("Unexpected return value for func1"); + } + + let func2_result = unsafe { wasm_runtime_call_indirect(exec_env, func2, 1, argv.as_mut_ptr()) }; + + if !func2_result { + println!("call func2 failed"); + return 0.0; + } + + if let WasmValue::F32(f2) = WasmValue::decode_to_f32(argv.clone()) { + assert_eq!(f2, n1 * 7.0); + n2 = f2; + } else { + println!("Unexpected return value for func1"); + } + + n1 + n2 +} + +fn main() -> Result<(), RuntimeError> { + let runtime = Runtime::builder() + .use_system_allocator() + .register_host_function(now) + .register_host_function(mystery) + .build()?; + + let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("examples/modules"); + d.push("basic_wasm32_unknown.wasm"); + let mut module = Module::from_file(&runtime, d.as_path())?; + + let wasi_ctx = WasiCtxBuilder::new() + .set_pre_open_path(vec!["."], vec![]) + .build(); + + module.set_wasi_context(wasi_ctx); + + let instance = Instance::new(&runtime, &module, 1024 * 64)?; + + let start_function = Function::find_export_func(&instance, "start")?; + let stop_function = Function::find_export_func(&instance, "stop")?; + let calc_function = Function::find_export_func(&instance, "calculate")?; + + let start_params: Vec = vec![]; + start_function.call(&instance, &start_params)?; + + let calc_params: Vec = vec![WasmValue::F32(3.0)]; + if let WasmValue::F32(value) = calc_function.call(&instance, &calc_params)? { + println!("Do a mystery calculation: input: 3, return: {}", value); + } else { + println!("Unexpected return value for calculate function"); + } + + let stop_params: Vec = vec![]; + if let WasmValue::I64(value) = stop_function.call(&instance, &stop_params)? { + println!("Time elapsed: {} ns", value); + } else { + println!("Unexpected return value for stop function"); + } + + Ok(()) +} diff --git a/examples/modules/basic/Cargo.lock b/examples/modules/basic/Cargo.lock new file mode 100644 index 0000000..ea38850 --- /dev/null +++ b/examples/modules/basic/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "basic" +version = "0.0.0" diff --git a/examples/modules/basic/Cargo.toml b/examples/modules/basic/Cargo.toml new file mode 100644 index 0000000..fea8ae9 --- /dev/null +++ b/examples/modules/basic/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "basic" +version = "0.0.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] diff --git a/examples/modules/basic/src/lib.rs b/examples/modules/basic/src/lib.rs new file mode 100644 index 0000000..96f73a0 --- /dev/null +++ b/examples/modules/basic/src/lib.rs @@ -0,0 +1,49 @@ +#![no_std] + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[link(wasm_import_module = "host")] +extern "C" { + fn now() -> i64; + fn mystery(n: f32, func1: usize, func2: usize) -> f32; +} + +static mut START_TIME: i64 = 0; +static mut TIMER_ACTIVE: bool = false; + +#[export_name = "start"] +pub fn start() { + unsafe { + START_TIME = now(); + TIMER_ACTIVE = true; + } +} + +#[export_name = "stop"] +pub fn stop() -> i64 { + unsafe { + if TIMER_ACTIVE { + TIMER_ACTIVE = false; + return now() - START_TIME; + } + 0 + } +} + +fn mul7(n: f32) -> f32 { + n * 7.0 +} + +fn mul5(n: f32) -> f32 { + n * 5.0 +} + +#[export_name = "calculate"] +pub fn calculate(n: f32) -> f32 { + unsafe { + mystery(n, mul5 as usize, mul7 as usize) + } +} diff --git a/examples/modules/basic_wasm32_unknown.wasm b/examples/modules/basic_wasm32_unknown.wasm new file mode 100644 index 0000000..1153475 Binary files /dev/null and b/examples/modules/basic_wasm32_unknown.wasm differ diff --git a/examples/wasi-hello/Cargo.lock b/examples/wasi-hello/Cargo.lock deleted file mode 100644 index 785bdd4..0000000 --- a/examples/wasi-hello/Cargo.lock +++ /dev/null @@ -1,324 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", -] - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "cc" -version = "1.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" -dependencies = [ - "shlex", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" -dependencies = [ - "cc", -] - -[[package]] -name = "either" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libloading" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" -dependencies = [ - "cfg-if", - "windows-sys", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "prettyplease" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "syn" -version = "2.0.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "wamr-rust-sdk" -version = "1.0.0" -source = "git+https://github.com/bytecodealliance/wamr-rust-sdk?tag=v1.1.0#b03ec6030b3f0ee9a190e59804ed87b2445635f6" -dependencies = [ - "wamr-sys", -] - -[[package]] -name = "wamr-sys" -version = "1.0.0" -source = "git+https://github.com/bytecodealliance/wamr-rust-sdk?tag=v1.1.0#b03ec6030b3f0ee9a190e59804ed87b2445635f6" -dependencies = [ - "bindgen", - "cc", - "cmake", -] - -[[package]] -name = "wasi-hello" -version = "0.1.0" -dependencies = [ - "wamr-rust-sdk", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/examples/wasi-hello/Cargo.toml b/examples/wasi-hello/Cargo.toml deleted file mode 100644 index eb62963..0000000 --- a/examples/wasi-hello/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (C) 2023 Liquid Reply GmbH. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -[package] -name = "wasi-hello" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0 WITH LLVM-exception" -authors = ["The WAMR Project Developers"] - -[dependencies] -wamr-rust-sdk = { git = "https://github.com/bytecodealliance/wamr-rust-sdk", tag = "v1.1.0" } diff --git a/examples/wasi-hello/gcd_wasm32_wasi.wasm b/examples/wasi-hello/gcd_wasm32_wasi.wasm deleted file mode 120000 index 52484c0..0000000 --- a/examples/wasi-hello/gcd_wasm32_wasi.wasm +++ /dev/null @@ -1 +0,0 @@ -../../resources/test/gcd_wasm32_wasi.wasm \ No newline at end of file diff --git a/examples/wasi-hello/src/main.rs b/examples/wasi-hello/src/main.rs deleted file mode 100644 index f27fa3e..0000000 --- a/examples/wasi-hello/src/main.rs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2023 Liquid Reply GmbH. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -use std::path::PathBuf; -use wamr_rust_sdk::{ - function::Function, instance::Instance, module::Module, runtime::Runtime, value::WasmValue, - wasi_context::WasiCtxBuilder, RuntimeError, -}; - -fn main() -> Result<(), RuntimeError> { - let runtime = Runtime::new()?; - - let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("gcd_wasm32_wasi.wasm"); - let mut module = Module::from_file(&runtime, d.as_path())?; - - let wasi_ctx = WasiCtxBuilder::new() - .set_pre_open_path(vec!["."], vec![]) - .build(); - - module.set_wasi_context(wasi_ctx); - - let instance = Instance::new(&runtime, &module, 1024 * 64)?; - - let function = Function::find_export_func(&instance, "gcd")?; - - let params: Vec = vec![WasmValue::I32(9), WasmValue::I32(27)]; - let result = function.call(&instance, ¶ms)?; - assert_eq!(result, WasmValue::I32(9)); - - Ok(()) -} diff --git a/src/function.rs b/src/function.rs index 9dabca4..5eea73e 100644 --- a/src/function.rs +++ b/src/function.rs @@ -8,8 +8,9 @@ use std::{ffi::CString, marker::PhantomData}; use wamr_sys::{ - wasm_exec_env_t, wasm_func_get_result_count, wasm_func_get_result_types, wasm_function_inst_t, - wasm_runtime_call_wasm, wasm_runtime_get_exception, wasm_runtime_get_exec_env_singleton, + wasm_exec_env_t, wasm_func_get_param_count, wasm_func_get_result_count, + wasm_func_get_result_types, wasm_function_inst_t, wasm_runtime_call_wasm, + wasm_runtime_get_exception, wasm_runtime_get_exec_env_singleton, wasm_runtime_get_wasi_exit_code, wasm_runtime_lookup_function, wasm_valkind_enum_WASM_F32, wasm_valkind_enum_WASM_F64, wasm_valkind_enum_WASM_I32, wasm_valkind_enum_WASM_I64, wasm_valkind_t, @@ -87,19 +88,32 @@ impl<'instance> Function<'instance> { instance: &'instance Instance<'instance>, params: &Vec, ) -> Result { + let param_count = + unsafe { wasm_func_get_param_count(self.function, instance.get_inner_instance()) }; + if param_count > params.len() as u32 { + return Err(RuntimeError::ExecutionError(ExecError { + message: "invalid parameters".to_string(), + exit_code: 0xff, + })); + } + // params -> Vec let mut argv = Vec::new(); for p in params { argv.append(&mut p.encode()); } - let argc = params.len(); + // Maintain sufficient allocated space in the vector rather than just declaring its capacity. + let result_count = + unsafe { wasm_func_get_result_count(self.function, instance.get_inner_instance()) }; + argv.resize(std::cmp::max(param_count, result_count * 2) as usize, 0); + let call_result: bool; unsafe { let exec_env: wasm_exec_env_t = wasm_runtime_get_exec_env_singleton(instance.get_inner_instance()); call_result = - wasm_runtime_call_wasm(exec_env, self.function, argc as u32, argv.as_mut_ptr()); + wasm_runtime_call_wasm(exec_env, self.function, param_count, argv.as_mut_ptr()); }; if !call_result { @@ -169,7 +183,7 @@ mod tests { let runtime = Runtime::new().unwrap(); let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("resources/test"); + d.push("tests/fixtures"); d.push("gcd_wasm32_wasi.wasm"); let module = Module::from_file(&runtime, d.as_path()); assert!(module.is_ok()); @@ -202,7 +216,7 @@ mod tests { let runtime = Runtime::new().unwrap(); let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("resources/test"); + d.push("tests/fixtures"); d.push("wasi-demo-app.wasm"); let module = Module::from_file(&runtime, d.as_path()); assert!(module.is_ok()); diff --git a/src/host_function.rs b/src/host_function.rs index 42bc75b..dfcca43 100644 --- a/src/host_function.rs +++ b/src/host_function.rs @@ -11,9 +11,29 @@ use wamr_sys::NativeSymbol; #[allow(dead_code)] #[derive(Debug)] -struct HostFunction { +pub struct HostFunction { function_name: CString, function_ptr: *mut c_void, + signature: CString, +} + +impl HostFunction { + pub fn new(name: &str, ptr: *mut c_void, signature: &str) -> Self { + HostFunction { + function_name: CString::new(name).unwrap(), + function_ptr: ptr, + signature: CString::new(signature).unwrap(), + } + } +} + +impl From for HostFunction +where + F: Fn() -> HostFunction, +{ + fn from(f: F) -> HostFunction { + f() + } } #[derive(Debug)] @@ -33,15 +53,21 @@ impl HostFunctionList { } } - pub fn register_host_function(&mut self, function_name: &str, function_ptr: *mut c_void) { - self.host_functions.push(HostFunction { - function_name: CString::new(function_name).unwrap(), - function_ptr, - }); + pub fn register_host_function>(&mut self, function: T) { + let host_function: HostFunction = function.into(); + + self.host_functions.push(host_function); let last = self.host_functions.last().unwrap(); self.native_symbols - .push(pack_host_function(&(last.function_name), function_ptr)); + .push( + NativeSymbol { + symbol: last.function_name.as_ptr(), + func_ptr: last.function_ptr, + signature: last.signature.as_ptr(), + attachment: ptr::null_mut(), + } + ) } pub fn get_native_symbols(&mut self) -> &mut Vec { @@ -53,54 +79,7 @@ impl HostFunctionList { } } -pub fn pack_host_function(function_name: &CString, function_ptr: *mut c_void) -> NativeSymbol { - NativeSymbol { - symbol: function_name.as_ptr(), - func_ptr: function_ptr, - signature: ptr::null(), - attachment: ptr::null_mut(), - } -} - #[cfg(test)] mod tests { - use super::*; - use crate::{ - function::Function, instance::Instance, module::Module, runtime::Runtime, value::WasmValue, - }; - use std::env; - use std::path::PathBuf; - - extern "C" fn extra() -> i32 { - 100 - } - - #[test] - #[ignore] - fn test_host_function() { - let runtime = Runtime::builder() - .use_system_allocator() - .register_host_function("extra", extra as *mut c_void) - .build() - .unwrap(); - - let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("resources/test"); - d.push("add_extra_wasm32_wasi.wasm"); - let module = Module::from_file(&runtime, d.as_path()); - assert!(module.is_ok()); - let module = module.unwrap(); - - let instance = Instance::new(&runtime, &module, 1024 * 64); - assert!(instance.is_ok()); - let instance: &Instance = &instance.unwrap(); - - let function = Function::find_export_func(instance, "add"); - assert!(function.is_ok()); - let function = function.unwrap(); - - let params: Vec = vec![WasmValue::I32(8), WasmValue::I32(8)]; - let result = function.call(instance, ¶ms); - assert_eq!(result.unwrap(), WasmValue::I32(116)); - } + // TODO: Replace with a unit test here. } diff --git a/src/lib.rs b/src/lib.rs index 2383a59..e550402 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,148 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -//! # WAMR Rust SDK -//! -//! ## Overview -//! -//! WAMR Rust SDK provides Rust language bindings for WAMR. It is the wrapper -//! of [*wasm_export.h*](../../../core/iwasm/include/wasm_export.h) but with Rust style. -//! It is more convenient to use WAMR in Rust with this crate. -//! -//! This crate contains API used to interact with Wasm modules. You can compile -//! modules, instantiate modules, call their export functions, etc. -//! Plus, as an embedded of Wasm, you can provide Wasm module functionality by -//! creating host-defined functions. -//! -//! WAMR Rust SDK includes a [*wamr-sys*](../crates/wamr-sys) crate. It will search for -//! the WAMR runtime source in the path *../..*. And then uses `rust-bindgen` durning -//! the build process to make a .so. -//! -//! This crate has similar concepts to the -//! [WebAssembly specification](https://webassembly.github.io/spec/core/). -//! -//! ### Core concepts -//! -//! - *Runtime*. It is the environment that hosts all the wasm modules. Each process has one runtime instance. -//! - *Module*. It is the compiled .wasm or .aot. It can be loaded into runtime and instantiated into instance. -//! - *Instance*. It is the running instance of a module. It can be used to call export functions. -//! - *Function*. It is the exported function. -//! -//! ### WASI concepts -//! -//! - *WASIArgs*. It is used to configure the WASI environment. -//! - *pre-open*. All files and directories in the list will be opened before the .wasm or .aot loaded. -//! - *allowed address*. All ip addresses in the *allowed address* list will be allowed to connect with a socket. -//! - *allowed DNS*. -//! -//! ### WAMR private concepts -//! -//! - *loading linking* instead of *instantiation linking*. *instantiation linking* is -//! used in Wasm JS API and Wasm C API. It means that every instance has its own, maybe -//! variant, imports. But *loading linking* means that all instances share the same *imports*. -//! -//! - *RuntimeArg*. Control runtime behavior. -//! - *running mode*. -//! - *allocator*. -//! -//! - *NativeFunction*. -//! -//! - *WasmValues*. -//! -//! ## Examples -//! -//! ### Example: to run a wasm32-wasi .wasm -//! -//! *wasm32-wasi* is a most common target for Wasm. It means that the .wasm is compiled with -//! `cargo build --target wasm32-wasi` or `wasi-sdk/bin/clang --target wasm32-wasi`. -//! -//! Say there is a gcd_wasm32_wasi.wasm which includes a function named *gcd*. It returns the GCD -//! of two parameters. -//! -//! The rust code to call the function would be: -//! -//! ``` -//! use wamr_rust_sdk::{ -//! runtime::Runtime, module::Module, instance::Instance, function::Function, -//! value::WasmValue, RuntimeError -//! }; -//! use std::path::PathBuf; -//! -//! fn main() -> Result<(), RuntimeError> { -//! let runtime = Runtime::new()?; -//! -//! let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); -//! d.push("resources/test"); -//! d.push("gcd_wasm32_wasi.wasm"); -//! -//! let module = Module::from_file(&runtime, d.as_path())?; -//! -//! let instance = Instance::new(&runtime, &module, 1024 * 64)?; -//! -//! let function = Function::find_export_func(&instance, "gcd")?; -//! -//! let params: Vec = vec![WasmValue::I32(9), WasmValue::I32(27)]; -//! let result = function.call(&instance, ¶ms)?; -//! assert_eq!(result, WasmValue::I32(9)); -//! -//! Ok(()) -//! } -//! ``` -//! -//! ### Example: more configuration for runtime. -//! -//! With more configuration, runtime is capable to run .wasm with variant features, like -//! - Wasm without WASI requirement. Usually, it means that the .wasm is compiled with `-nostdlib` -//! or `--target wasm32-unknown-unknown` -//! - Configure runtime. -//! - Provides host-defined functions to meet import requirements. -//! -//! Say there is an add_extra_wasm32_wasi.wasm. Its exported function, `add()`, -//! requires an imported function, `extra()`, during the execution. The `add()` -//! adds two parameters and the result of `extra()` . It is like `a + b + extra()`. -//! -//! The rust code to call the *add* function is like this: -//! -//! ``` -//! use wamr_rust_sdk::{ -//! runtime::Runtime, module::Module, instance::Instance, function::Function, -//! value::WasmValue, RuntimeError -//! }; -//! use std::path::PathBuf; -//! use std::ffi::c_void; -//! -//! extern "C" fn extra() -> i32 { -//! 100 -//! } -//! -//! fn main() -> Result<(), RuntimeError> { -//! let runtime = Runtime::builder() -//! .use_system_allocator() -//! .register_host_function("extra", extra as *mut c_void) -//! .build()?; -//! -//! let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); -//! d.push("resources/test"); -//! d.push("add_extra_wasm32_wasi.wasm"); -//! let module = Module::from_file(&runtime, d.as_path())?; -//! -//! let instance = Instance::new(&runtime, &module, 1024 * 64)?; -//! -//! let function = Function::find_export_func(&instance, "add")?; -//! -//! let params: Vec = vec![WasmValue::I32(9), WasmValue::I32(27)]; -//! let result = function.call(&instance, ¶ms)?; -//! assert_eq!(result, WasmValue::I32(136)); -//! -//! Ok(()) -//! } -//! ``` -//! + #![doc = include_str!("../README.md")] + +#[cfg(feature = "macros")] +pub extern crate wamr_macros; + +use std::{error, fmt, io}; -use std::error; -use std::fmt; -use std::io; pub use wamr_sys as sys; +pub use wamr_macros::generate_host_function; pub mod function; mod helper; diff --git a/src/module.rs b/src/module.rs index 68cbba5..34c8f48 100644 --- a/src/module.rs +++ b/src/module.rs @@ -243,7 +243,7 @@ mod tests { let runtime = Runtime::new().unwrap(); let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("resources/test"); + d.push("tests/fixtures"); d.push("gcd_wasm32_wasi.wasm"); let module = Module::from_file(&runtime, d.as_path()); assert!(module.is_ok()); diff --git a/src/runtime.rs b/src/runtime.rs index 2109fd0..32eb63e 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -15,7 +15,7 @@ use wamr_sys::{ RunningMode_Mode_Interp, RunningMode_Mode_LLVM_JIT, RuntimeInitArgs, }; -use crate::{host_function::HostFunctionList, RuntimeError}; +use crate::{host_function::{HostFunction, HostFunctionList}, RuntimeError}; #[allow(dead_code)] #[derive(Debug)] @@ -68,15 +68,19 @@ pub struct RuntimeBuilder { /// Can't build() until config allocator mode impl Default for RuntimeBuilder { fn default() -> Self { - let args = RuntimeInitArgs::default(); - RuntimeBuilder { - args, - host_functions: HostFunctionList::new("host"), - } + Self::new("host") } } impl RuntimeBuilder { + /// create a named module runtime builder + pub fn new(name: &str) -> Self { + Self { + args: RuntimeInitArgs::default(), + host_functions: HostFunctionList::new(name), + } + } + /// system allocator mode /// allocate memory from system allocator for runtime consumed memory pub fn use_system_allocator(mut self) -> RuntimeBuilder { @@ -108,13 +112,8 @@ impl RuntimeBuilder { } /// register a host function - pub fn register_host_function( - mut self, - function_name: &str, - function_ptr: *mut c_void, - ) -> RuntimeBuilder { - self.host_functions - .register_host_function(function_name, function_ptr); + pub fn register_host_function>(mut self, function: T) -> RuntimeBuilder { + self.host_functions.register_host_function(function); self } diff --git a/resources/test/add-extra/Cargo.lock b/tests/fixtures/add-extra/Cargo.lock similarity index 100% rename from resources/test/add-extra/Cargo.lock rename to tests/fixtures/add-extra/Cargo.lock diff --git a/resources/test/add-extra/Cargo.toml b/tests/fixtures/add-extra/Cargo.toml similarity index 83% rename from resources/test/add-extra/Cargo.toml rename to tests/fixtures/add-extra/Cargo.toml index c0ca5e8..7497aaa 100644 --- a/resources/test/add-extra/Cargo.toml +++ b/tests/fixtures/add-extra/Cargo.toml @@ -3,9 +3,12 @@ [package] name = "add_extra" -version = "0.1.0" +version = "0.0.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +crate-type = ["cdylib", "rlib"] + [dependencies] diff --git a/resources/test/add-extra/src/main.rs b/tests/fixtures/add-extra/src/lib.rs similarity index 77% rename from resources/test/add-extra/src/main.rs rename to tests/fixtures/add-extra/src/lib.rs index 64071bd..1c02c89 100644 --- a/resources/test/add-extra/src/main.rs +++ b/tests/fixtures/add-extra/src/lib.rs @@ -12,7 +12,3 @@ extern "C" { pub fn add_ex(m: u32, n: u32) -> u32 { m + n + unsafe { extra() } } - -fn main() { - println!("Hello, world! Please call add(10, 20) to see the result."); -} diff --git a/resources/test/add_extra_wasm32_wasi.wasm b/tests/fixtures/add_extra_wasm32_wasi.wasm old mode 100755 new mode 100644 similarity index 100% rename from resources/test/add_extra_wasm32_wasi.wasm rename to tests/fixtures/add_extra_wasm32_wasi.wasm diff --git a/resources/test/gcd/Cargo.lock b/tests/fixtures/gcd/Cargo.lock similarity index 100% rename from resources/test/gcd/Cargo.lock rename to tests/fixtures/gcd/Cargo.lock diff --git a/resources/test/gcd/Cargo.toml b/tests/fixtures/gcd/Cargo.toml similarity index 82% rename from resources/test/gcd/Cargo.toml rename to tests/fixtures/gcd/Cargo.toml index 07d9576..067efcf 100644 --- a/resources/test/gcd/Cargo.toml +++ b/tests/fixtures/gcd/Cargo.toml @@ -3,9 +3,12 @@ [package] name = "gcd" -version = "0.1.0" +version = "0.0.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +crate-type = ["cdylib", "rlib"] + [dependencies] diff --git a/resources/test/gcd/src/main.rs b/tests/fixtures/gcd/src/lib.rs similarity index 79% rename from resources/test/gcd/src/main.rs rename to tests/fixtures/gcd/src/lib.rs index d4f190d..519ac39 100644 --- a/resources/test/gcd/src/main.rs +++ b/tests/fixtures/gcd/src/lib.rs @@ -15,7 +15,3 @@ pub fn gcd(m: u32, n: u32) -> u32 { println!("gcd({}, {}) = {}", m, n, a); a } - -fn main() { - println!("Hello, world! Please call gcd(10, 5) to see the result."); -} diff --git a/resources/test/gcd_wasm32_wasi.wasm b/tests/fixtures/gcd_wasm32_wasi.wasm old mode 100755 new mode 100644 similarity index 100% rename from resources/test/gcd_wasm32_wasi.wasm rename to tests/fixtures/gcd_wasm32_wasi.wasm diff --git a/tests/fixtures/type/Cargo.toml b/tests/fixtures/type/Cargo.toml new file mode 100644 index 0000000..b3c0ff2 --- /dev/null +++ b/tests/fixtures/type/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "type" +version = "0.0.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] diff --git a/tests/fixtures/type/src/lib.rs b/tests/fixtures/type/src/lib.rs new file mode 100644 index 0000000..77e3b29 --- /dev/null +++ b/tests/fixtures/type/src/lib.rs @@ -0,0 +1,41 @@ + +#[export_name = "return_i32"] +pub fn return_i32() -> i32 { + i32::MAX +} + +#[export_name = "param_i32"] +pub fn param_i32(v: i32) -> i32 { + v +} + +#[export_name = "return_u32"] +pub fn return_u32() -> u32 { + u32::MAX +} + +#[export_name = "param_u32"] +pub fn param_u32(v: u32) -> u32 { + v +} + +#[export_name = "return_i64"] +pub fn return_i64() -> i64 { + i64::MAX +} + +#[export_name = "param_i64"] +pub fn param_i64(v: i64) -> i64 { + v +} + +#[export_name = "return_u64"] +pub fn return_u64() -> u64 { + u64::MAX +} + +#[export_name = "param_u64"] +pub fn param_u64(v: u64) -> u64 { + v +} + diff --git a/resources/test/wasi-demo-app.wasm b/tests/fixtures/wasi-demo-app.wasm old mode 100755 new mode 100644 similarity index 100% rename from resources/test/wasi-demo-app.wasm rename to tests/fixtures/wasi-demo-app.wasm diff --git a/tests/host_function_test.rs b/tests/host_function_test.rs new file mode 100644 index 0000000..5d19297 --- /dev/null +++ b/tests/host_function_test.rs @@ -0,0 +1,40 @@ +use std::env; +use std::path::PathBuf; + +use wamr_rust_sdk::{ + function::Function, generate_host_function, instance::Instance, module::Module, + runtime::Runtime, value::WasmValue, +}; + +#[generate_host_function] +fn extra() -> i32 { + 100 +} + +#[test] +fn test_host_function() { + let runtime = Runtime::builder() + .use_system_allocator() + .register_host_function(extra) + .build() + .unwrap(); + + let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("tests/fixtures"); + d.push("add_extra_wasm32_wasi.wasm"); + let module = Module::from_file(&runtime, d.as_path()); + assert!(module.is_ok()); + let module = module.unwrap(); + + let instance = Instance::new(&runtime, &module, 1024 * 64); + assert!(instance.is_ok()); + let instance: &Instance = &instance.unwrap(); + + let function = Function::find_export_func(instance, "add"); + assert!(function.is_ok()); + let function = function.unwrap(); + + let params: Vec = vec![WasmValue::I32(8), WasmValue::I32(8)]; + let result = function.call(instance, ¶ms); + assert_eq!(result.unwrap(), WasmValue::I32(116)); +} diff --git a/tests/type_test.rs b/tests/type_test.rs new file mode 100644 index 0000000..e69de29