diff --git a/crates/api/src/func.rs b/crates/api/src/func.rs index 9e09c7070a..95b78f913f 100644 --- a/crates/api/src/func.rs +++ b/crates/api/src/func.rs @@ -16,14 +16,131 @@ use wasmtime_runtime::{InstanceHandle, VMContext, VMFunctionBody}; /// * A user-defined function used to satisfy an import. /// /// These types of callable items are all wrapped up in this `Func` and can be -/// used to both instantiate an [`Instance`](crate::Instance) as well as be -/// extracted from an [`Instance`](crate::Instance). +/// used to both instantiate an [`Instance`] as well as be extracted from an +/// [`Instance`]. +/// +/// [`Instance`]: crate::Instance /// /// # `Func` and `Clone` /// /// Functions are internally reference counted so you can `clone` a `Func`. The /// cloning process only performs a shallow clone, so two cloned `Func` /// instances are equivalent in their functionality. +/// +/// # Examples +/// +/// One way to get a `Func` is from an [`Instance`] after you've instantiated +/// it: +/// +/// ``` +/// # use wasmtime::*; +/// # fn main() -> anyhow::Result<()> { +/// let store = Store::default(); +/// let module = Module::new(&store, r#"(module (func (export "foo")))"#)?; +/// let instance = Instance::new(&module, &[])?; +/// let foo = instance.exports()[0].func().expect("export wasn't a function"); +/// +/// // Work with `foo` as a `Func` at this point, such as calling it +/// // dynamically... +/// match foo.call(&[]) { +/// Ok(result) => { /* ... */ } +/// Err(trap) => { +/// panic!("execution of `foo` resulted in a wasm trap: {}", trap); +/// } +/// } +/// foo.call(&[])?; +/// +/// // ... or we can make a static assertion about its signature and call it. +/// // Our first call here can fail if the signatures don't match, and then the +/// // second call can fail if the function traps (like the `match` above). +/// let foo = foo.get0::<()>()?; +/// foo()?; +/// # Ok(()) +/// # } +/// ``` +/// +/// You can also use the [`wrap*` family of functions](Func::wrap1) to create a +/// `Func` +/// +/// ``` +/// # use wasmtime::*; +/// # fn main() -> anyhow::Result<()> { +/// let store = Store::default(); +/// +/// // Create a custom `Func` which can execute arbitrary code inside of the +/// // closure. +/// let add = Func::wrap2(&store, |a: i32, b: i32| -> i32 { a + b }); +/// +/// // Next we can hook that up to a wasm module which uses it. +/// let module = Module::new( +/// &store, +/// r#" +/// (module +/// (import "" "" (func $add (param i32 i32) (result i32))) +/// (func (export "call_add_twice") (result i32) +/// i32.const 1 +/// i32.const 2 +/// call $add +/// i32.const 3 +/// i32.const 4 +/// call $add +/// i32.add)) +/// "#, +/// )?; +/// let instance = Instance::new(&module, &[add.into()])?; +/// let call_add_twice = instance.exports()[0].func().expect("export wasn't a function"); +/// let call_add_twice = call_add_twice.get0::()?; +/// +/// assert_eq!(call_add_twice()?, 10); +/// # Ok(()) +/// # } +/// ``` +/// +/// Or you could also create an entirely dynamic `Func`! +/// +/// ``` +/// # use wasmtime::*; +/// use std::rc::Rc; +/// +/// struct Double; +/// +/// impl Callable for Double { +/// fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Trap> { +/// let mut value = params[0].unwrap_i32(); +/// value *= 2; +/// results[0] = value.into(); +/// Ok(()) +/// } +/// } +/// +/// # fn main() -> anyhow::Result<()> { +/// let store = Store::default(); +/// +/// // Here we need to define the type signature of our `Double` function and +/// // then wrap it up in a `Func` +/// let double_type = wasmtime::FuncType::new( +/// Box::new([wasmtime::ValType::I32]), +/// Box::new([wasmtime::ValType::I32]) +/// ); +/// let double = Func::new(&store, double_type, Rc::new(Double)); +/// +/// let module = Module::new( +/// &store, +/// r#" +/// (module +/// (import "" "" (func $double (param i32) (result i32))) +/// (func $start +/// i32.const 1 +/// call $double +/// drop) +/// (start $start)) +/// "#, +/// )?; +/// let instance = Instance::new(&module, &[double.into()])?; +/// // .. work with `instance` if necessary +/// # Ok(()) +/// # } +/// ``` #[derive(Clone)] pub struct Func { _store: Store, @@ -186,7 +303,6 @@ impl Func { /// function being called is known statically so the type signature can /// be inferred. Rust types will map to WebAssembly types as follows: /// - /// /// | Rust Argument Type | WebAssembly Type | /// |--------------------|------------------| /// | `i32` | `i32` | @@ -209,6 +325,98 @@ impl Func { /// possible for when WebAssembly calls the function provided. With /// sufficient inlining and optimization the WebAssembly will call /// straight into `func` provided, with no extra fluff entailed. + /// + /// # Examples + /// + /// First up we can see how simple wasm imports can be implemented, such + /// as a function that adds its two arguments and returns the result. + /// + /// ``` + /// # use wasmtime::*; + /// # fn main() -> anyhow::Result<()> { + /// # let store = Store::default(); + /// let add = Func::wrap2(&store, |a: i32, b: i32| a + b); + /// let module = Module::new( + /// &store, + /// r#" + /// (module + /// (import "" "" (func $add (param i32 i32) (result i32))) + /// (func (export "foo") (param i32 i32) (result i32) + /// local.get 0 + /// local.get 1 + /// call $add)) + /// "#, + /// )?; + /// let instance = Instance::new(&module, &[add.into()])?; + /// let foo = instance.exports()[0].func().unwrap().get2::()?; + /// assert_eq!(foo(1, 2)?, 3); + /// # Ok(()) + /// # } + /// ``` + /// + /// We can also do the same thing, but generate a trap if the addition + /// overflows: + /// + /// ``` + /// # use wasmtime::*; + /// # fn main() -> anyhow::Result<()> { + /// # let store = Store::default(); + /// let add = Func::wrap2(&store, |a: i32, b: i32| { + /// match a.checked_add(b) { + /// Some(i) => Ok(i), + /// None => Err(Trap::new("overflow")), + /// } + /// }); + /// let module = Module::new( + /// &store, + /// r#" + /// (module + /// (import "" "" (func $add (param i32 i32) (result i32))) + /// (func (export "foo") (param i32 i32) (result i32) + /// local.get 0 + /// local.get 1 + /// call $add)) + /// "#, + /// )?; + /// let instance = Instance::new(&module, &[add.into()])?; + /// let foo = instance.exports()[0].func().unwrap().get2::()?; + /// assert_eq!(foo(1, 2)?, 3); + /// assert!(foo(i32::max_value(), 1).is_err()); + /// # Ok(()) + /// # } + /// ``` + /// + /// And don't forget all the wasm types are supported! + /// + /// ``` + /// # use wasmtime::*; + /// # fn main() -> anyhow::Result<()> { + /// # let store = Store::default(); + /// let debug = Func::wrap4(&store, |a: i32, b: f32, c: i64, d: f64| { + /// println!("a={}", a); + /// println!("b={}", b); + /// println!("c={}", c); + /// println!("d={}", d); + /// }); + /// let module = Module::new( + /// &store, + /// r#" + /// (module + /// (import "" "" (func $debug (param i32 f32 i64 f64))) + /// (func (export "foo") + /// i32.const 1 + /// f32.const 2 + /// i64.const 3 + /// f64.const 4 + /// call $debug)) + /// "#, + /// )?; + /// let instance = Instance::new(&module, &[debug.into()])?; + /// let foo = instance.exports()[0].func().unwrap().get0::<()>()?; + /// foo()?; + /// # Ok(()) + /// # } + /// ``` (wrap1, A1) /// Creates a new `Func` from the given Rust closure, which takes 2 diff --git a/docs/embed-rust.md b/docs/embed-rust.md index 3ec437a518..391f42103c 100644 --- a/docs/embed-rust.md +++ b/docs/embed-rust.md @@ -1,14 +1,21 @@ # Embedding Wasmtime in Rust -This document shows how to embed Wasmtime using the Rust API, and run a simple -wasm program. +This document shows an example of how to embed Wasmtime using the [Rust +API][apidoc] to execute a simple wasm program. Be sure to also check out the +[full API documentation][apidoc] for a full listing of what the [`wasmtime` +crate][crate] has to offer. -# Create some wasm +[apidoc]: https://bytecodealliance.github.io/wasmtime/api/wasmtime/ +[wasmtime]: https://crates.io/crates/wasmtime -Let's create a simple WebAssembly file with a single exported function that returns an integer: +## Creating the WebAssembly to execute + +Creation of a WebAssembly file is generally covered by the [Writing +WebAssembly chapter](./wasm.md), so we'll just assume that you've already got a +wasm file on hand for the rest of this tutorial. To make things simple we'll +also just assume you've got a `hello.wat` file which looks like this: ```wat -(;; wat2wasm hello.wat -o $WASM_FILES/hello.wasm ;;) (module (func (export "answer") (result i32) i32.const 42 @@ -16,135 +23,148 @@ Let's create a simple WebAssembly file with a single exported function that retu ) ``` -# Create rust project +Here we're just exporting one function which returns an integer that we'll read +from Rust. + +## Hello, World! + +First up let's create a rust project ```sh $ cargo new --bin wasmtime_hello $ cd wasmtime_hello -$ cp $WASM_FILES/hello.wasm . ``` -We will be using the wasmtime engine/API to run the wasm file, so we will add the dependency to `Cargo.toml`: +Next you'll want to add `hello.wat` to the root of your project. + +We will be using the `wasmtime` crate to run the wasm file, so next up we need a +dependency in `Cargo.toml`: ```toml [dependencies] -wasmtime = "" +wasmtime = "0.12.0" ``` -where "" is the current version number of the `wasmtime` crate. - -It is time to add code to the `src/main.rs`. First, storage needs to be activated: - -```rust -# extern crate wasmtime; -use wasmtime::*; - -let store = Store::default(); -``` - -The `hello.wasm` can be read from the file system and provided to the `Module` object constructor as `&[u8]`: - -```rust,no_run -# extern crate wasmtime; -# use wasmtime::*; -# fn main() -> Result<(), Box> { -# let store = Store::default(); -use std::fs::read; - -let hello_wasm = read("hello.wasm")?; - -let module = Module::new(&store, &hello_wasm)?; -# Ok(()) -# } -``` - -The module instance can now be created. Normally, you would provide imports, but -in this case, there are none required: - -```rust -# extern crate wasmtime; -# use wasmtime::*; -# fn main() -> Result<(), Box> { -# let store = Store::default(); -# let module = Module::new(&store, "(module)")?; -let instance = Instance::new(&module, &[])?; -# Ok(()) -# } -``` - -Everything is set. If a WebAssembly module has a start function -- it was run. -The instance's exports can be used at this point. wasmtime provides functions -to get an export by name, and ensure that it's a function: - -```rust -# extern crate wasmtime; -# use wasmtime::*; -# fn main() -> Result<(), Box> { -# let store = Store::default(); -# let module = Module::new(&store, r#"(module (func (export "answer")))"#)?; -# let instance = Instance::new(&module, &[])?; -let answer = instance.get_export("answer").expect("answer").func().expect("function"); -# Ok(()) -# } -``` - -The exported function can be called using the `call` method. The exported -"answer" function accepts no parameters and returns a single `i32` value. - -```rust -# extern crate wasmtime; -# use wasmtime::*; -# fn main() -> Result<(), Box> { -# let store = Store::default(); -# let module = Module::new(&store, r#"(module (func (export "answer") (result i32) i32.const 2))"#)?; -# let instance = Instance::new(&module, &[])?; -# let answer = instance.get_export("answer").expect("answer").func().expect("function"); -let result = answer.call(&[])?; -println!("Answer: {:?}", result[0].i32()); -# Ok(()) -# } -``` - -Since we know the signature of the function ahead of time, we can also assert -its signature and call the function directly without doing conversions: - -```rust -# extern crate wasmtime; -# use wasmtime::*; -# fn main() -> Result<(), Box> { -# let store = Store::default(); -# let module = Module::new(&store, r#"(module (func (export "answer") (result i32) i32.const 2))"#)?; -# let instance = Instance::new(&module, &[])?; -# let answer = instance.get_export("answer").expect("answer").func().expect("function"); -let answer = answer.get0::()?; -let result: i32 = answer()?; -println!("Answer: {}", result); -# Ok(()) -# } -``` - -The names of the WebAssembly module's imports and exports can be discovered by -means of module's corresponding methods. - -# src/main.rs +Next up let's write the code that we need to execute this wasm file. The +simplest version of this looks like so: ```rust,no_run # extern crate wasmtime; use std::error::Error; -use std::fs::read; use wasmtime::*; fn main() -> Result<(), Box> { + // A `Store` is a sort of "global object" in a sense, but for now it suffices + // to say that it's generally passed to most constructors. let store = Store::default(); - let wasm = read("hello.wasm")?; +# if false { + // We start off by creating a `Module` which represents a compiled form + // of our input wasm module. In this case it'll be JIT-compiled after + // we parse the text format. + let module = Module::from_file(&store, "hello.wat")?; +# } +# let module = Module::new(&store, r#"(module (func (export "answer") (result i32) i32.const 42))"#)?; - let module = Module::new(&store, &wasm)?; + // After we have a compiled `Module` we can then instantiate it, creating + // an `Instance` which we can actually poke at functions on. let instance = Instance::new(&module, &[])?; - let answer = instance.get_export("answer").expect("answer").func().expect("function"); - let result = answer.call(&[])?; - println!("Answer: {:?}", result[0].i32()); + // The `Instance` gives us access to various exported functions and items, + // which we access here to pull out our `answer` exported function and + // run it. + let answer = instance.get_export("answer") + .expect("export named `answer` not found") + .func() + .expect("export `answer` was not a function"); + + // There's a few ways we can call the `answer` `Func` value. The easiest + // is to statically assert its signature with `get0` (in this case asserting + // it takes no arguments and returns one i32) and then call it. + let answer = answer.get0::()?; + + // And finally we can call our function! Note that the error propagation + // with `?` is done to handle the case where the wasm function traps. + let result = answer()?; + println!("Answer: {:?}", result); Ok(()) } ``` + +We can build and execute our example with `cargo run`. Note that by depending on +`wasmtime` you're depending on a JIT compiler, so it may take a moment to build +all of its dependencies: + +```sh +$ cargo run + Compiling ... + ... + Finished dev [unoptimized + debuginfo] target(s) in 42.32s + Running `wasmtime_hello/target/debug/wasmtime_hello` +Answer: 42 +``` + +and there we go! We've now executed our first WebAssembly in `wasmtime` and +gotten the result back. + +## Importing Host Functionality + +What we've just seen is a pretty small example of how to call a wasm function +and take a look at the result. Most interesting wasm modules, however, are going +to import some functions to do something a bit more interesting. For that you'll +need to provide imported functions from Rust for wasm to call! + +Let's take a look at a wasm module which imports a logging function as well as +some simple arithmetic from the environment. + +```wat +(module + (import "" "log" (func $log (param i32))) + (import "" "double" (func $double (param i32) (result i32))) + (func (export "run") (result i32) + i32.const 0 + call $log + i32.const 1 + call $log + i32.const 2 + call $double + call $log + ) +) +``` + +This wasm module will call our `"log"` import a few times and then also call the +`"double"` import. We can compile and instantiate this module with code that +looks like this: + +```rust,no_run +# extern crate wasmtime; +# use std::error::Error; +# use wasmtime::*; +# fn main() -> Result<(), Box> { +# let store = Store::default(); +# let module = Module::new(&store, r#" +# (module +# (import "" "log" (func $log (param i32))) +# (import "" "double" (func $double (param i32) (result i32))))"#)?; +// First we can create our `log` function, which will simply print out the +// parameter it receives. +let log = Func::wrap1(&store, |param: i32| { + println!("log: {}", param); +}); + +// Next we can create our double function which doubles the input it receives. +let double = Func::wrap1(&store, |param: i32| param * 2); + +// When instantiating the module we now need to provide the imports to the +// instantiation process. This is the second slice argument, where each +// entry in the slice must line up with the imports in the module. +let instance = Instance::new(&module, &[log.into(), double.into()])?; +# Ok(()) +# } +``` + +Note that there's a number of ways to define a `Func`, be sure to [consult its +documentation][`Func`] for other ways to create a host-defined function. + +[`Func`]: https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Func.html