You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
2.6 KiB

//! This is an example of working with multi-value modules and dealing with
//! multi-value functions.
//!
//! Note that the `Func::wrap*` interfaces cannot be used to return multiple
//! values just yet, so we need to use the more dynamic `Func::new` and
//! `Func::call` methods.
// You can execute this example with `cargo run --example multi`
use anyhow::{format_err, Result};
use wasmtime::*;
Migrate from failure to thiserror and anyhow (#436) * Migrate from failure to thiserror and anyhow The failure crate invents its own traits that don't use std::error::Error (because failure predates certain features added to Error); this prevents using ? on an error from failure in a function using Error. The thiserror and anyhow crates integrate with the standard Error trait instead. This change does not attempt to semantically change or refactor the approach to error-handling in any portion of the code, to ensure that the change remains straightforward to review. Modules using specific differentiated error types move from failure_derive and derive(Fail) to thiserror and derive(Error). Modules boxing all errors opaquely move from failure::Error to anyhow. Modules using String as an error type continue to do so. Code using unwrap or expect continues to do so. Drop Display implementations when thiserror can easily derive an identical instance. Drop manual traversal of iter_causes; anyhow's Debug instance prints the chain of causes by default. Use anyhow's type alias anyhow::Result<T> in place of std::result::Result<T, anyhow::Error> whenever possible. * wasm2obj: Simplify error handling using existing messages handle_module in wasm2obj manually maps cranelift_codegen::isa::LookupError values to strings, but LookupError values already have strings that say almost exactly the same thing. Rely on the strings from cranelift. * wasmtime: Rely on question-mark-in-main The main() wrapper around rmain() completely matches the behavior of question-mark-in-main (print error to stderr and return 1), so switch to question-mark-in-main. * Update to walrus 0.13 and wasm-webidl-bindings 0.6 Both crates switched from failure to anyhow; updating lets us avoid a translation from failure to anyhow within wasmtime-interface-types.
5 years ago
fn main() -> Result<()> {
println!("Initializing...");
let engine = Engine::default();
let store = Store::new(&engine);
// Compile.
println!("Compiling module...");
let module = Module::from_file(&engine, "examples/multi.wat")?;
// Create external print functions.
println!("Creating callback...");
let callback_type = FuncType::new(
Box::new([ValType::I32, ValType::I64]),
Box::new([ValType::I64, ValType::I32]),
);
let callback_func = Func::new(&store, callback_type, |_, args, results| {
println!("Calling back...");
println!("> {} {}", args[0].unwrap_i32(), args[1].unwrap_i64());
results[0] = Val::I64(args[1].unwrap_i64() + 1);
results[1] = Val::I32(args[0].unwrap_i32() + 1);
Ok(())
});
// Instantiate.
println!("Instantiating module...");
let instance = Instance::new(&store, &module, &[callback_func.into()])?;
// Extract exports.
println!("Extracting export...");
let g = instance
Refactor (#1524) * Compute instance exports on demand. Instead having instances eagerly compute a Vec of Externs, and bumping the refcount for each Extern, compute Externs on demand. This also enables `Instance::get_export` to avoid doing a linear search. This also means that the closure returned by `get0` and friends now holds an `InstanceHandle` to dynamically hold the instance live rather than being scoped to a lifetime. * Compute module imports and exports on demand too. And compute Extern::ty on demand too. * Add a utility function for computing an ExternType. * Add a utility function for looking up a function&#39;s signature. * Add a utility function for computing the ValType of a Global. * Rename wasmtime_environ::Export to EntityIndex. This helps differentiate it from other Export types in the tree, and describes what it is. * Fix a typo in a comment. * Simplify module imports and exports. * Make `Instance::exports` return the export names. This significantly simplifies the public API, as it&#39;s relatively common to need the names, and this avoids the need to do a zip with `Module::exports`. This also changes `ImportType` and `ExportType` to have public members instead of private members and accessors, as I find that simplifies the usage particularly in cases where there are temporary instances. * Remove `Instance::module`. This doesn&#39;t quite remove `Instance`&#39;s `module` member, it gets a step closer. * Use a InstanceHandle utility function. * Don&#39;t consume self in the `Func::get*` methods. Instead, just create a closure containing the instance handle and the export for them to call. * Use `ExactSizeIterator` to avoid needing separate `num_*` methods. * Rename `Extern::func()` etc. to `into_func()` etc. * Revise examples to avoid using `nth`. * Add convenience methods to instance for getting specific extern types. * Use the convenience functions in more tests and examples. * Avoid cloning strings for `ImportType` and `ExportType`. * Remove more obviated clone() calls. * Simplify `Func`&#39;s closure state. * Make wasmtime::Export&#39;s fields private. This makes them more consistent with ExportType. * Fix compilation error. * Make a lifetime parameter explicit, and use better lifetime names. Instead of &#39;me, use &#39;instance and &#39;module to make it clear what the lifetime is. * More lifetime cleanups.
5 years ago
.get_func("g")
.ok_or(format_err!("failed to find export `g`"))?;
// Call `$g`.
println!("Calling export \"g\"...");
let results = g.call(&[Val::I32(1), Val::I64(3)])?;
println!("Printing result...");
println!("> {} {}", results[0].unwrap_i64(), results[1].unwrap_i32());
assert_eq!(results[0].unwrap_i64(), 4);
assert_eq!(results[1].unwrap_i32(), 2);
// Call `$round_trip_many`.
println!("Calling export \"round_trip_many\"...");
let round_trip_many = instance
Refactor (#1524) * Compute instance exports on demand. Instead having instances eagerly compute a Vec of Externs, and bumping the refcount for each Extern, compute Externs on demand. This also enables `Instance::get_export` to avoid doing a linear search. This also means that the closure returned by `get0` and friends now holds an `InstanceHandle` to dynamically hold the instance live rather than being scoped to a lifetime. * Compute module imports and exports on demand too. And compute Extern::ty on demand too. * Add a utility function for computing an ExternType. * Add a utility function for looking up a function&#39;s signature. * Add a utility function for computing the ValType of a Global. * Rename wasmtime_environ::Export to EntityIndex. This helps differentiate it from other Export types in the tree, and describes what it is. * Fix a typo in a comment. * Simplify module imports and exports. * Make `Instance::exports` return the export names. This significantly simplifies the public API, as it&#39;s relatively common to need the names, and this avoids the need to do a zip with `Module::exports`. This also changes `ImportType` and `ExportType` to have public members instead of private members and accessors, as I find that simplifies the usage particularly in cases where there are temporary instances. * Remove `Instance::module`. This doesn&#39;t quite remove `Instance`&#39;s `module` member, it gets a step closer. * Use a InstanceHandle utility function. * Don&#39;t consume self in the `Func::get*` methods. Instead, just create a closure containing the instance handle and the export for them to call. * Use `ExactSizeIterator` to avoid needing separate `num_*` methods. * Rename `Extern::func()` etc. to `into_func()` etc. * Revise examples to avoid using `nth`. * Add convenience methods to instance for getting specific extern types. * Use the convenience functions in more tests and examples. * Avoid cloning strings for `ImportType` and `ExportType`. * Remove more obviated clone() calls. * Simplify `Func`&#39;s closure state. * Make wasmtime::Export&#39;s fields private. This makes them more consistent with ExportType. * Fix compilation error. * Make a lifetime parameter explicit, and use better lifetime names. Instead of &#39;me, use &#39;instance and &#39;module to make it clear what the lifetime is. * More lifetime cleanups.
5 years ago
.get_func("round_trip_many")
.ok_or(format_err!("failed to find export `round_trip_many`"))?;
let args = vec![
Val::I64(0),
Val::I64(1),
Val::I64(2),
Val::I64(3),
Val::I64(4),
Val::I64(5),
Val::I64(6),
Val::I64(7),
Val::I64(8),
Val::I64(9),
];
let results = round_trip_many.call(&args)?;
println!("Printing result...");
print!(">");
for r in results.iter() {
print!(" {}", r.unwrap_i64());
}
println!();
assert_eq!(results.len(), 10);
assert!(args
.iter()
.zip(results.iter())
.all(|(a, r)| a.i64() == r.i64()));
Ok(())
}