summaryrefslogtreecommitdiff
path: root/examples/funcref_callbacks.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/funcref_callbacks.rs')
-rw-r--r--examples/funcref_callbacks.rs71
1 files changed, 27 insertions, 44 deletions
diff --git a/examples/funcref_callbacks.rs b/examples/funcref_callbacks.rs
index 01f833c..4ee7438 100644
--- a/examples/funcref_callbacks.rs
+++ b/examples/funcref_callbacks.rs
@@ -1,21 +1,17 @@
use eyre::Result;
use tinywasm::{Extern, FuncContext, Imports, Module, Store, types::FuncRef};
+const LHS: i32 = 5;
+const RHS: i32 = 3;
+
fn main() -> Result<()> {
- by_func_ref_passed()?;
- by_func_ref_returned()?;
+ run_passed_funcref_example()?;
+ run_returned_funcref_example()?;
Ok(())
}
-/// Example of passing Wasm functions (as `funcref`) to an imported host function
-/// and the imported host function calling them.
-fn by_func_ref_passed() -> Result<()> {
- // A module with:
- // - Imported function "host.call_this" that accepts a callback.
- // - Exported Wasm function "tell_host_to_call" that calls "host.call_this" with Wasm functions $add and $sub.
- // - Wasm functions $add and $sub and an imported function $mul used as callbacks
- // (just to show that imported functions can be referenced too).
- // - Exported Wasm function "call_binop_by_ref", a proxy used by the host to call func-references of type (i32, i32) -> i32.
+fn run_passed_funcref_example() -> Result<()> {
+ // Host receives funcref and calls it via an exported proxy.
const WASM: &str = r#"
(module
(import "host" "call_this" (func $host_callback_caller (param funcref)))
@@ -30,7 +26,7 @@ fn by_func_ref_passed() -> Result<()> {
(type $binop (func (param i32 i32) (result i32)))
(table 3 funcref)
- (elem (i32.const 0) $add $sub $host_mul) ;; Function can only be referenced if added to a table.
+ (elem (i32.const 0) $add $sub $host_mul)
(func $add (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
@@ -50,51 +46,41 @@ fn by_func_ref_passed() -> Result<()> {
)
"#;
- let wasm = wat::parse_str(WASM).expect("Failed to parse WAT");
+ let wasm = wat::parse_str(WASM).expect("failed to parse wat");
let module = Module::parse_bytes(&wasm)?;
let mut store = Store::default();
let mut imports = Imports::new();
- // Import host function that takes callbacks and calls them.
imports.define(
"host",
"call_this",
- Extern::typed_func(|mut ctx: FuncContext<'_>, fn_ref: FuncRef| -> tinywasm::Result<()> {
- let proxy_caller =
+ Extern::typed_func(|mut ctx: FuncContext<'_>, func_ref: FuncRef| -> tinywasm::Result<()> {
+ // Host cannot call a funcref directly, so it routes through Wasm.
+ let call_by_ref =
ctx.module().exported_func::<(FuncRef, i32, i32), i32>(ctx.store(), "call_binop_by_ref")?;
- // Call the callback we got as an argument using "call_binop_by_ref".
- let res = proxy_caller.call(ctx.store_mut(), (fn_ref, 5, 3))?;
- println!("(funcref {fn_ref:?})(5,3) results in {res}");
+ let result = call_by_ref.call(ctx.store_mut(), (func_ref, LHS, RHS))?;
+ println!("(funcref {func_ref:?})({LHS},{RHS}) results in {result}");
Ok(())
}),
)?;
- // Import host.mul function (one of the functions whose references are taken).
imports.define(
"host",
"mul",
- Extern::typed_func(|_, args: (i32, i32)| -> tinywasm::Result<i32> { Ok(args.0 * args.1) }),
+ Extern::typed_func(|_, (lhs, rhs): (i32, i32)| -> tinywasm::Result<i32> { Ok(lhs * rhs) }),
)?;
let instance = module.instantiate(&mut store, Some(imports))?;
let caller = instance.exported_func::<(), ()>(&store, "tell_host_to_call")?;
- // Call "tell_host_to_call".
caller.call(&mut store, ())?;
- // An interesting detail is that neither $add, $sub, nor $mul were exported,
- // but with a little help from the proxy "call_binop_by_ref", references to them are callable by the host.
+
Ok(())
}
-/// Example of returning a Wasm function as a callback to a host function
-/// and the host function calling it.
-fn by_func_ref_returned() -> Result<()> {
- // A module with:
- // - An exported function "what_should_host_call" that returns 3 `funcref`s.
- // - Wasm functions $add and $sub and an imported function $mul used as callbacks
- // (just to show that imported functions can be referenced too).
- // - Another exported Wasm function "call_binop_by_ref", a proxy used by the host to call func-references of type (i32, i32) -> i32
+fn run_returned_funcref_example() -> Result<()> {
+ // Wasm returns funcref values, host executes them through the same proxy.
const WASM: &str = r#"
(module
(import "host" "mul" (func $host_mul (param $x i32) (param $y i32) (result i32)))
@@ -125,33 +111,30 @@ fn by_func_ref_returned() -> Result<()> {
)
"#;
- let wasm = wat::parse_str(WASM).expect("Failed to parse WAT");
+ let wasm = wat::parse_str(WASM).expect("failed to parse wat");
let module = Module::parse_bytes(&wasm)?;
let mut store = Store::default();
let mut imports = Imports::new();
- // Import host.mul function (one of the possible operations).
imports.define(
"host",
"mul",
- Extern::typed_func(|_, args: (i32, i32)| -> tinywasm::Result<i32> { Ok(args.0 * args.1) }),
+ Extern::typed_func(|_, (lhs, rhs): (i32, i32)| -> tinywasm::Result<i32> { Ok(lhs * rhs) }),
)?;
let instance = module.instantiate(&mut store, Some(imports))?;
- // Ask the module what to call.
- let funcrefs = {
- let address_getter =
+ let (add_ref, sub_ref, mul_ref) = {
+ let get_funcrefs =
instance.exported_func::<(), (FuncRef, FuncRef, FuncRef)>(&store, "what_should_host_call")?;
- address_getter.call(&mut store, ())?
+ get_funcrefs.call(&mut store, ())?
};
- let proxy_caller = instance.exported_func::<(FuncRef, i32, i32), i32>(&store, "call_binop_by_ref")?;
+ let call_by_ref = instance.exported_func::<(FuncRef, i32, i32), i32>(&store, "call_binop_by_ref")?;
- for (idx, func_ref) in [funcrefs.0, funcrefs.1, funcrefs.2].iter().enumerate() {
- // Call those `funcref`s via "call_binop_by_ref".
- let res = proxy_caller.call(&mut store, (*func_ref, 5, 3))?;
- println!("At idx: {idx}, funcref {func_ref:?}(5,3) results in {res}");
+ for (idx, func_ref) in [add_ref, sub_ref, mul_ref].iter().enumerate() {
+ let result = call_by_ref.call(&mut store, (*func_ref, LHS, RHS))?;
+ println!("At idx: {idx}, funcref {func_ref:?}({LHS},{RHS}) results in {result}");
}
Ok(())
}