Expand top-level wasmtime crate docs (#1955)
This is something I meant to do a long time ago but forgot to get around to it! This commit updates the top-level documentation of the `wasmtime` crate to have examples, more words, and generall be a bit more up-to-date and complete.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2336,6 +2336,7 @@ dependencies = [
|
||||
"wasmtime-jit",
|
||||
"wasmtime-profiling",
|
||||
"wasmtime-runtime",
|
||||
"wasmtime-wasi",
|
||||
"wat",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@@ -31,6 +31,7 @@ winapi = "0.3.7"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.0"
|
||||
wasmtime-wasi = { path = "../wasi" }
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
@@ -1,10 +1,233 @@
|
||||
//! Wasmtime's embedding API
|
||||
//!
|
||||
//! This crate contains a high-level API used to interact with WebAssembly
|
||||
//! modules. The API here is intended to mirror the proposed [WebAssembly C
|
||||
//! API](https://github.com/WebAssembly/wasm-c-api), with small extensions here
|
||||
//! and there to implement Rust idioms. This crate also defines the actual C API
|
||||
//! itself for consumption from other languages.
|
||||
//! This crate contains an API used to interact with WebAssembly modules. For
|
||||
//! example you can compile modules, instantiate them, call them, etc. As an
|
||||
//! embedder of WebAssembly you can also provide WebAssembly modules
|
||||
//! functionality from the host by creating host-defined functions, memories,
|
||||
//! globals, etc, which can do things that WebAssembly cannot (such as print to
|
||||
//! the screen).
|
||||
//!
|
||||
//! The `wasmtime` crate draws inspiration from a number of sources, including
|
||||
//! the [JS WebAssembly
|
||||
//! API](https://developer.mozilla.org/en-US/docs/WebAssembly) as well as the
|
||||
//! [proposed C API](https://github.com/webassembly/wasm-c-api). As with all
|
||||
//! other Rust code you're guaranteed that programs will be safe (not have
|
||||
//! undefined behavior or segfault) so long as you don't use `unsafe` in your
|
||||
//! own program. With `wasmtime` you can easily and conveniently embed a
|
||||
//! WebAssembly runtime with confidence that the WebAssembly is safely
|
||||
//! sandboxed.
|
||||
//!
|
||||
//! An example of using Wasmtime looks like:
|
||||
//!
|
||||
//! ```
|
||||
//! use anyhow::Result;
|
||||
//! use wasmtime::*;
|
||||
//!
|
||||
//! fn main() -> Result<()> {
|
||||
//! // All wasm objects operate within the context of a "store"
|
||||
//! let store = Store::default();
|
||||
//!
|
||||
//! // Modules can be compiled through either the text or binary format
|
||||
//! let wat = r#"
|
||||
//! (module
|
||||
//! (import "" "" (func $host_hello (param i32)))
|
||||
//!
|
||||
//! (func (export "hello")
|
||||
//! i32.const 3
|
||||
//! call $host_hello)
|
||||
//! )
|
||||
//! "#;
|
||||
//! let module = Module::new(store.engine(), wat)?;
|
||||
//!
|
||||
//! // Host functions can be defined which take/return wasm values and
|
||||
//! // execute arbitrary code on the host.
|
||||
//! let host_hello = Func::wrap(&store, |param: i32| {
|
||||
//! println!("Got {} from WebAssembly", param);
|
||||
//! });
|
||||
//!
|
||||
//! // Instantiation of a module requires specifying its imports and then
|
||||
//! // afterwards we can fetch exports by name, as well as asserting the
|
||||
//! // type signature of the function with `get0`.
|
||||
//! let instance = Instance::new(&store, &module, &[host_hello.into()])?;
|
||||
//! let hello = instance
|
||||
//! .get_func("hello")
|
||||
//! .ok_or(anyhow::format_err!("failed to find `hello` function export"))?
|
||||
//! .get0::<()>()?;
|
||||
//!
|
||||
//! // And finally we can call the wasm as if it were a Rust function!
|
||||
//! hello()?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Core Concepts
|
||||
//!
|
||||
//! There are a number of core types and concepts that are important to be aware
|
||||
//! of when using the `wasmtime` crate:
|
||||
//!
|
||||
//! * Reference counting - almost all objects in this API are reference counted.
|
||||
//! Most of the time when and object is `clone`d you're just bumping a
|
||||
//! reference count. For example when you clone an [`Instance`] that is a
|
||||
//! cheap operation, it doesn't create an entirely new instance.
|
||||
//!
|
||||
//! * [`Store`] - all WebAssembly object and host values will be "connected" to
|
||||
//! a store. A [`Store`] is not threadsafe which means that itself and all
|
||||
//! objects connected to it are pinned to a single thread (this happens
|
||||
//! automatically through a lack of the `Send` and `Sync` traits). Similarly
|
||||
//! `wasmtime` does not have a garbage collector so anything created within a
|
||||
//! [`Store`] will not be deallocated until all references have gone away. See
|
||||
//! the [`Store`] documentation for more information.
|
||||
//!
|
||||
//! * [`Module`] - a compiled WebAssembly module. This structure represents
|
||||
//! in-memory JIT code which is ready to execute after being instantiated.
|
||||
//! It's often important to cache instances of a [`Module`] because creation
|
||||
//! (compilation) can be expensive. Note that [`Module`] is safe to share
|
||||
//! across threads.
|
||||
//!
|
||||
//! * [`Instance`] - an instantiated WebAssembly module. An instance is where
|
||||
//! you can actually acquire a [`Func`] from, for example, to call. Each
|
||||
//! [`Instance`], like all other [`Store`]-connected objects, cannot be sent
|
||||
//! across threads.
|
||||
//!
|
||||
//! There are other important types within the `wasmtime` crate but it's crucial
|
||||
//! to be familiar with the above types! Be sure to browse the API documentation
|
||||
//! to get a feeling for what other functionality is offered by this crate.
|
||||
//!
|
||||
//! ## Example Architecture
|
||||
//!
|
||||
//! To better understand how Wasmtime types interact with each other let's walk
|
||||
//! through, at a high-level, an example of how you might use WebAssembly. In
|
||||
//! our use case let's say we have a web server where we'd like to run some
|
||||
//! custom WebAssembly on each request. To ensure requests are isolated from
|
||||
//! each other, though, we'll be creating a new [`Instance`] for each request.
|
||||
//!
|
||||
//! When the server starts, we'll start off by creating an [`Engine`] (and maybe
|
||||
//! tweaking [`Config`] settings if necessary). This [`Engine`] will be the only
|
||||
//! engine for the lifetime of the server itself.
|
||||
//!
|
||||
//! Next, we can compile our WebAssembly. You'd create a [`Module`] through the
|
||||
//! [`Module::new`] API. This will generate JIT code and perform expensive
|
||||
//! compilation tasks up-front.
|
||||
//!
|
||||
//! After that setup, the server starts up as usual and is ready to receive
|
||||
//! requests. Upon receiving a request you'd then create a [`Store`] with
|
||||
//! [`Store::new`] referring to the original [`Engine`]. Using your [`Module`]
|
||||
//! from before you'd then call [`Instance::new`] to instantiate our module for
|
||||
//! the request. Both of these operations are designed to be as cheap as
|
||||
//! possible.
|
||||
//!
|
||||
//! With an [`Instance`] you can then invoke various exports and interact with
|
||||
//! the WebAssembly module. Once the request is finished the [`Store`],
|
||||
//! [`Instance`], and all other items loaded are dropped and everything will be
|
||||
//! deallocated. Note that it's crucial to create a [`Store`]-per-request to
|
||||
//! ensure that memory usage doesn't balloon accidentally by keeping a [`Store`]
|
||||
//! alive indefinitely.
|
||||
//!
|
||||
//! ## Advanced Linking
|
||||
//!
|
||||
//! Often WebAssembly modules are not entirely self-isolated. They might refer
|
||||
//! to quite a few pieces of host functionality, WASI, or maybe even a number of
|
||||
//! other wasm modules. To help juggling all this together this crate provides a
|
||||
//! [`Linker`] type which serves as an abstraction to assist in instantiating a
|
||||
//! module. The [`Linker`] type also transparently handles Commands and Reactors
|
||||
//! as defined by WASI.
|
||||
//!
|
||||
//! ## WASI
|
||||
//!
|
||||
//! The `wasmtime` crate does not natively provide support for WASI, but you can
|
||||
//! use the `wasmtime-wasi` crate for that purpose. With `wasmtime-wasi` you can
|
||||
//! create a "wasi instance" and then add all of its items into a [`Linker`],
|
||||
//! which can then be used to instantiate a [`Module`] that uses WASI.
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! In addition to the examples below be sure to check out the [online embedding
|
||||
//! documentation][rustdocs] as well as the [online list of examples][examples]
|
||||
//!
|
||||
//! [rustdocs]: https://bytecodealliance.github.io/wasmtime/lang-rust.html
|
||||
//! [examples]: https://bytecodealliance.github.io/wasmtime/examples-rust-embed.html
|
||||
//!
|
||||
//! An example of using WASI looks like:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use anyhow::Result;
|
||||
//! # use wasmtime::*;
|
||||
//! use wasmtime_wasi::{Wasi, WasiCtx};
|
||||
//!
|
||||
//! # fn main() -> Result<()> {
|
||||
//! let store = Store::default();
|
||||
//! let mut linker = Linker::new(&store);
|
||||
//!
|
||||
//! // Create an instance of `Wasi` which contains a `WasiCtx`. Note that
|
||||
//! // `WasiCtx` provides a number of ways to configure what the target program
|
||||
//! // will have access to.
|
||||
//! let wasi = Wasi::new(&store, WasiCtx::new(std::env::args())?);
|
||||
//! wasi.add_to_linker(&mut linker)?;
|
||||
//!
|
||||
//! // Instantiate our module with the imports we've created, and run it.
|
||||
//! let module = Module::from_file(store.engine(), "foo.wasm")?;
|
||||
//! let instance = linker.instantiate(&module)?;
|
||||
//! // ...
|
||||
//!
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! An example of reading a string from a wasm module:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::str;
|
||||
//!
|
||||
//! # use wasmtime::*;
|
||||
//! # fn main() -> anyhow::Result<()> {
|
||||
//! let store = Store::default();
|
||||
//! let log_str = Func::wrap(&store, |caller: Caller<'_>, ptr: i32, len: i32| {
|
||||
//! let mem = match caller.get_export("memory") {
|
||||
//! Some(Extern::Memory(mem)) => mem,
|
||||
//! _ => return Err(Trap::new("failed to find host memory")),
|
||||
//! };
|
||||
//!
|
||||
//! // We're reading raw wasm memory here so we need `unsafe`. Note
|
||||
//! // though that this should be safe because we don't reenter wasm
|
||||
//! // while we're reading wasm memory, nor should we clash with
|
||||
//! // any other memory accessors (assuming they're well-behaved
|
||||
//! // too).
|
||||
//! unsafe {
|
||||
//! let data = mem.data_unchecked()
|
||||
//! .get(ptr as u32 as usize..)
|
||||
//! .and_then(|arr| arr.get(..len as u32 as usize));
|
||||
//! let string = match data {
|
||||
//! Some(data) => match str::from_utf8(data) {
|
||||
//! Ok(s) => s,
|
||||
//! Err(_) => return Err(Trap::new("invalid utf-8")),
|
||||
//! },
|
||||
//! None => return Err(Trap::new("pointer/length out of bounds")),
|
||||
//! };
|
||||
//! assert_eq!(string, "Hello, world!");
|
||||
//! println!("{}", string);
|
||||
//! }
|
||||
//! Ok(())
|
||||
//! });
|
||||
//! let module = Module::new(
|
||||
//! store.engine(),
|
||||
//! r#"
|
||||
//! (module
|
||||
//! (import "" "" (func $log_str (param i32 i32)))
|
||||
//! (func (export "foo")
|
||||
//! i32.const 4 ;; ptr
|
||||
//! i32.const 13 ;; len
|
||||
//! call $log_str)
|
||||
//! (memory (export "memory") 1)
|
||||
//! (data (i32.const 4) "Hello, world!"))
|
||||
//! "#,
|
||||
//! )?;
|
||||
//! let instance = Instance::new(&store, &module, &[log_str.into()])?;
|
||||
//! let foo = instance.get_func("foo").unwrap().get0::<()>()?;
|
||||
//! foo()?;
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![deny(missing_docs, intra_doc_link_resolution_failure)]
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
|
||||
@@ -784,11 +784,25 @@ impl Default for Engine {
|
||||
|
||||
// Store
|
||||
|
||||
/// A `Store` is a shared cache of information between WebAssembly modules.
|
||||
/// A `Store` is a collection of WebAssembly instances and host-defined items.
|
||||
///
|
||||
/// Each `Module` is compiled into a `Store` and a `Store` is associated with an
|
||||
/// [`Engine`]. You'll use a `Store` to attach to a number of global items in
|
||||
/// the production of various items for wasm modules.
|
||||
/// All WebAssembly instances and items will be attached to and refer to a
|
||||
/// `Store`. For example instances, functions, globals, and tables are all
|
||||
/// attached to a `Store`. Instances are created by instantiating a [`Module`]
|
||||
/// within a `Store`.
|
||||
///
|
||||
/// `Store` is not thread-safe and cannot be sent to other threads. All items
|
||||
/// which refer to a `Store` additionally are not threadsafe and can only be
|
||||
/// used on the original thread that they were created on.
|
||||
///
|
||||
/// A `Store` is not intended to be a long-lived object in a program. No form of
|
||||
/// GC is implemented at this time so once an instance is created within a
|
||||
/// `Store` it will not be deallocated until all references to the `Store` have
|
||||
/// gone away (this includes all references to items in the store). This makes
|
||||
/// `Store` unsuitable for creating an unbounded number of instances in it
|
||||
/// because `Store` will never release this memory. It's instead recommended to
|
||||
/// have a long-lived [`Engine`] and instead create a `Store` for a more scoped
|
||||
/// portion of your application.
|
||||
///
|
||||
/// # Stores and `Clone`
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user