Run a WebAssembly function with WasmEdge low-level Rust APIs
Overview
This section demonstrates how to use the Rust APIs of the wasmedge-sys
crate to run a host function.
As you may know, several mainstream programming languages, such as C/C++, Rust, Go, and Python, support compiling their programs into WebAssembly binary. In this demo, we'll introduce how to use the APIs defined in Vm
of wasmedge-sys
crate to call a WebAssembly function which could be coded in any programming language mentioned above.
The code in the example is verified on
- wasmedge-sys v0.10.0
- wasmedge-types v0.3.0
Example
We use fibonacci.wasm
in this demo, and the contents of the WebAssembly file are presented below. The statement, (export "fib" (func $fib))
, declares an exported function named fib
. This function computes a Fibonacci number with a given i32
number as input. We'll use the function name later to achieve the goal of computing a Fibonacci number.
(module
(export "fib" (func $fib))
(func $fib (param $n i32) (result i32)
(if
(i32.lt_s
(get_local $n)
(i32.const 2)
)
(return
(i32.const 1)
)
)
(return
(i32.add
(call $fib
(i32.sub
(get_local $n)
(i32.const 2)
)
)
(call $fib
(i32.sub
(get_local $n)
(i32.const 1)
)
)
)
)
)
)
Step 1: Create a WasmEdge AST Module
In this step, we'll create a WasmEdge AST Module
instance from a WebAssembly file.
-
First, create a
Loader
context; -
Then, load a specified WebAssebly file ("fibonacci.wasm") via the
from_file
method of theLoader
context. If the process is successful, then a WasmEdgeAST Module
instance is returned.
#![allow(unused)] fn main() { use wasmedge_sys::Loader; use std::path::PathBuf; // create a Loader context let loader = Loader::create(None).expect("fail to create a Loader context"); // load a wasm module from a specified wasm file, and return a WasmEdge AST Module instance let path = PathBuf::from("fibonacci.wasm"); let module = loader.from_file(path).expect("fail to load the WebAssembly file"); }
Step 2: Create a WasmEdge Vm
context
In WasmEdge, a Vm
defines a running environment, in which all varieties of instances and contexts are stored and maintained. In the demo code below, we explicitly create a WasmEdge Store
context, and then use it as one of the inputs in the creation of a Vm
context. If not specify a Store
context explicitly, then Vm
will create a store by itself.
#![allow(unused)] fn main() { use wasmedge_sys::{Config, Store, Vm}; // create a Config context let config = Config::create().expect("fail to create a Config context"); // create a Store context let mut store = Store::create().expect("fail to create a Store context"); // create a Vm context with the given Config and Store let mut vm = Vm::create(Some(config), Some(&mut store)).expect("fail to create a Vm context"); }
Step 3: Invoke the fib
function
In Step 1, we got a module that hosts the target fib
function defined in the WebAssembly. Now, we can call the function via the run_wasm_from_module
method of the Vm
context by passing the exported function name, fib
.
#![allow(unused)] fn main() { use wasmedge_sys::WasmValue; // run a function let returns = vm.run_wasm_from_module(module, "fib", [WasmValue::from_i32(5)]).expect("fail to run the target function in the module"); println!("The result of fib(5) is {}", returns[0].to_i32()); }
This is the final result printing on the screen:
The result of fib(5) is 8