Run a WebAssembly function with WasmEdge low-level Rust APIs

Prerequisites

This example uses the following crates:

  • wasmedge-sys v0.7.0
  • wasmedge-types v0.1.1

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.

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 the Loader context. If the process is successful, then a WasmEdge AST Module instance is returned.

  1. #![allow(unused)]
  2. fn main() {
  3. use wasmedge_sys::Loader;
  4. use std::path::PathBuf;
  5. // create a Loader context
  6. let loader = Loader::create(None).expect("fail to create a Loader context");
  7. // load a wasm module from a specified wasm file, and return a WasmEdge AST Module instance
  8. let path = PathBuf::from("fibonacci.wasm");
  9. let module = loader.from_file(path).expect("fail to load the WebAssembly file");
  10. }

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.

  1. #![allow(unused)]
  2. fn main() {
  3. use wasmedge_sys::{Config, Store, Vm};
  4. // create a Config context
  5. let config = Config::create().expect("fail to create a Config context");
  6. // create a Store context
  7. let mut store = Store::create().expect("fail to create a Store context");
  8. // create a Vm context with the given Config and Store
  9. let mut vm = Vm::create(Some(config), Some(&mut store)).expect("fail to create a Vm context");
  10. }

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.

  1. #![allow(unused)]
  2. fn main() {
  3. use wasmedge_sys::WasmValue;
  4. // run a function
  5. let returns = vm.run_wasm_from_module(module, "fib", [WasmValue::from_i32(5)]).expect("fail to run the target function in the module");
  6. println!("The result of fib(5) is {}", returns[0].to_i32());
  7. }

This is the final result printing on the screen:

The result of fib(5) is 8