Browse Source

Update and add lots of docs, mostly for components (#7862)

* Update and add lots of docs, mostly for components

When I originally implemented the embedding API for the component model
I left a lot of `// TODO: say more here` style comments assuming I'd
come back around before stabilization. While I didn't quite make it in
time for Wasmtime 17 this is my attempt to improve things for the
future. This should add substantive documentation for all component-model
related things and flesh out some more details here and there. Nowhere
near comprehensive but, hey, Rome wasn't built in a day either.

* Update crates/wasmtime/src/runtime/component/component.rs

Co-authored-by: Jeff Parsons <jeff@parsons.io>

* Update crates/wasmtime/src/runtime/component/component.rs

Co-authored-by: Jeff Parsons <jeff@parsons.io>

---------

Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com>
Co-authored-by: Jeff Parsons <jeff@parsons.io>
pull/7880/head
Alex Crichton 9 months ago
committed by GitHub
parent
commit
6d105f4d84
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      crates/wasmtime/src/config.rs
  2. 391
      crates/wasmtime/src/lib.rs
  3. 129
      crates/wasmtime/src/runtime/component/component.rs
  4. 77
      crates/wasmtime/src/runtime/component/func.rs
  5. 110
      crates/wasmtime/src/runtime/component/func/typed.rs
  6. 17
      crates/wasmtime/src/runtime/component/instance.rs
  7. 377
      crates/wasmtime/src/runtime/component/mod.rs
  8. 150
      crates/wasmtime/src/runtime/component/values.rs
  9. 19
      crates/wasmtime/src/runtime/func.rs
  10. 51
      crates/wasmtime/src/runtime/module.rs
  11. 16
      crates/wasmtime/src/runtime/store.rs

4
crates/wasmtime/src/config.rs

@ -28,7 +28,9 @@ use wasmtime_fiber::RuntimeFiberStackCreator;
pub use wasmtime_environ::CacheStore;
#[cfg(feature = "pooling-allocator")]
pub use wasmtime_runtime::{mpk, MpkEnabled};
use wasmtime_runtime::mpk;
#[cfg(feature = "pooling-allocator")]
pub use wasmtime_runtime::MpkEnabled;
/// Represents the module instance allocation strategy to use.
#[derive(Clone)]

391
crates/wasmtime/src/lib.rs

@ -1,37 +1,52 @@
//! Wasmtime's embedding API
//! # Wasmtime's embedding API
//!
//! Wasmtime is a WebAssembly engine for JIT-compiled or ahead-of-time compiled
//! WebAssembly modules. More information about the Wasmtime project as a whole
//! can be found [in the documentation book](https://docs.wasmtime.dev) whereas
//! this documentation mostly focuses on the API reference of the `wasmtime`
//! crate itself.
//!
//! 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 has similar concepts to the
//! the [JS WebAssembly
//! WebAssembly modules and components. More information about the Wasmtime
//! project as a whole can be found [in the documentation
//! book](https://docs.wasmtime.dev) whereas this documentation mostly focuses
//! on the API reference of the `wasmtime` crate itself.
//!
//! This crate contains an API used to interact with [WebAssembly modules] or
//! [WebAssembly components]. For example you can compile WebAssembly, create
//! instances, call functions, etc. As an embedder of WebAssembly you can also
//! provide guests 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).
//!
//! [WebAssembly modules]: https://webassembly.github.io/spec
//! [WebAssembly components]: https://component-model.bytecodealliance.org
//!
//! The `wasmtime` crate is designed to be safe, efficient, and ergonomic.
//! This enables executing WebAssembly without the embedder needing to use
//! `unsafe` code, meaning that you're guaranteed there is no undefined behavior
//! or segfaults in either the WebAssembly guest or the host itself.
//!
//! The `wasmtime` crate can roughly be thought of as being split into two
//! halves:
//!
//! * One half of the crate is similar to 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), but the Rust
//! API is designed for efficiency, ergonomics, and expressivity in Rust. 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.
//! [proposed C API](https://github.com/webassembly/wasm-c-api) and is
//! intended for working with [WebAssembly modules]. This API resides in the
//! root of the `wasmtime` crate's namespace, for example
//! [`wasmtime::Module`](`Module`).
//!
//! An example of using Wasmtime looks like:
//! * The second half of the crate is for use with the [WebAssembly Component
//! Model]. The implementation of the component model is present in
//! [`wasmtime::component`](`component`) and roughly mirrors the structure for
//! core WebAssembly, for example [`component::Func`] mirrors [`Func`].
//!
//! [WebAssembly Component Model]: https://component-model.bytecodealliance.org
//!
//! An example of using Wasmtime to run a core WebAssembly module looks like:
//!
//! ```
//! use wasmtime::*;
//!
//! fn main() -> wasmtime::Result<()> {
//! // Modules can be compiled through either the text or binary format
//! let engine = Engine::default();
//!
//! // Modules can be compiled through either the text or binary format
//! let wat = r#"
//! (module
//! (import "host" "host_func" (func $host_hello (param i32)))
@ -43,19 +58,23 @@
//! "#;
//! let module = Module::new(&engine, wat)?;
//!
//! // Host functionality can be arbitrary Rust functions and is provided
//! // to guests through a `Linker`.
//! let mut linker = Linker::new(&engine);
//! linker.func_wrap("host", "host_func", |caller: Caller<'_, u32>, param: i32| {
//! println!("Got {} from WebAssembly", param);
//! println!("my host state is: {}", caller.data());
//! })?;
//!
//! // All wasm objects operate within the context of a "store". Each
//! // `Store` has a type parameter to store host-specific data, which in
//! // this case we're using `4` for.
//! let mut store = Store::new(&engine, 4);
//! let host_func = Func::wrap(&mut store, |caller: Caller<'_, u32>, param: i32| {
//! println!("Got {} from WebAssembly", param);
//! println!("my host state is: {}", caller.data());
//! });
//! let mut store: Store<u32> = Store::new(&engine, 4);
//!
//! // 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 `get_typed_func`.
//! let instance = Instance::new(&mut store, &module, &[host_func.into()])?;
//! let instance = linker.instantiate(&mut store, &module)?;
//! let hello = instance.get_typed_func::<(), ()>(&mut store, "hello")?;
//!
//! // And finally we can call the wasm!
@ -70,19 +89,13 @@
//! There are a number of core types and concepts that are important to be aware
//! of when using the `wasmtime` crate:
//!
//! * [`Engine`] - a global compilation environment for WebAssembly. An
//! [`Engine`] is an object that can be shared concurrently across threads and
//! is created with a [`Config`] to tweak various settings. Compilation of any
//! WebAssembly requires first configuring and creating an [`Engine`].
//!
//! * [`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, and can be created from a WebAssembly binary and an
//! [`Engine`] with [`Module::new`]. Caching can either happen with
//! [`Engine::precompile_module`] or [`Module::serialize`], feeding those
//! bytes back into [`Module::deserialize`].
//! * [`Engine`] - a global compilation and runtime environment for WebAssembly.
//! An [`Engine`] is an object that can be shared concurrently across threads
//! and is created with a [`Config`] with many knobs for configuring
//! behavior. Compiling or executing any WebAssembly requires first
//! configuring and creating an [`Engine`]. All [`Module`]s and
//! [`Component`](component::Component)s belong to an [`Engine`], and
//! typically there's one [`Engine`] per process.
//!
//! * [`Store`] - container for all information related to WebAssembly objects
//! such as functions, instances, memories, etc. A [`Store<T>`][`Store`]
@ -92,19 +105,48 @@
//! required for all WebAssembly operations, such as calling a wasm function.
//! The [`Store`] is passed in as a "context" to methods like [`Func::call`].
//! Dropping a [`Store`] will deallocate all memory associated with
//! WebAssembly objects within the [`Store`].
//!
//! * [`Instance`] - an instantiated WebAssembly module. An instance is where
//! you can actually acquire a [`Func`] from, for example, to call.
//!
//! * [`Func`] - a WebAssembly (or host) function. This can be acquired as the
//! export of an [`Instance`] to call WebAssembly functions, or it can be
//! created via functions like [`Func::wrap`] to wrap host-defined
//! functionality and give it to WebAssembly.
//!
//! * [`Table`], [`Global`], [`Memory`] - other WebAssembly objects which can
//! either be defined on the host or in wasm itself (via instances). These all
//! have various ways of being interacted with like [`Func`].
//! WebAssembly objects within the [`Store`]. A [`Store`] is cheap to create
//! and destroy and does not GC objects such as unused instances internally,
//! so it's intended to be short-lived (or no longer than the instances it
//! contains).
//!
//! * [`Linker`] (or [`component::Linker`]) - host functions are defined within
//! a linker to provide them a string-based name which can be looked up when
//! instantiating a WebAssembly module or component. Linkers are traditionally
//! populated at startup and then reused for all future instantiations of all
//! instances, assuming the set of host functions does not change over time.
//! Host functions are `Fn(..) + Send + Sync` and typically do not close over
//! mutable state. Instead it's recommended to store mutable state in the `T`
//! of [`Store<T>`] which is accessed through [`Caller<'_,
//! T>`](crate::Caller) provided to host functions.
//!
//! * [`Module`] (or [`Component`](component::Component)) - a compiled
//! WebAssembly module or component. These structures contain compiled
//! executable code from a WebAssembly binary which is ready to execute after
//! being instantiated. These are expensive to create as they require
//! compilation of the input WebAssembly. Modules and components are safe to
//! share across threads, however. Modules and components can additionally be
//! [serialized into a list of bytes](crate::Module::serialize) to later be
//! [deserialized](crate::Module::deserialize) quickly. This enables JIT-style
//! compilation through constructors such as [`Module::new`] and AOT-style
//! compilation by having the compilation process use [`Module::serialize`]
//! and the execution process use [`Module::deserialize`].
//!
//! * [`Instance`] (or [`component::Instance`]) - an instantiated WebAssembly
//! module or component. An instance is where you can actually acquire a
//! [`Func`] (or [`component::Func`]) from, for example, to call.
//!
//! * [`Func`] (or [`component::Func`]) - a WebAssembly function. This can be
//! acquired as the export of an [`Instance`] to call WebAssembly functions,
//! or it can be created via functions like [`Func::wrap`] to wrap
//! host-defined functionality and give it to WebAssembly. Functions also have
//! typed views as [`TypedFunc`] or [`component::TypedFunc`] for a more
//! efficient calling convention.
//!
//! * [`Table`], [`Global`], [`Memory`], [`component::Resource`] - other
//! WebAssembly objects which can either be defined on the host or in wasm
//! itself (via instances). These all have various ways of being interacted
//! with like [`Func`].
//!
//! All "store-connected" types such as [`Func`], [`Memory`], etc, require the
//! store to be passed in as a context to each method. Methods in wasmtime
@ -124,90 +166,6 @@
//! [`Func`] point within the [`Store`] and require the [`Store`] to be provided
//! to actually access the internals of the WebAssembly function, for instance.
//!
//! ## Linking
//!
//! WebAssembly modules almost always require functionality from the host to
//! perform I/O-like tasks. They might refer to quite a few pieces of host
//! functionality, WASI, or maybe even a number of other wasm modules. To assist
//! with managing this a [`Linker`] type is provided to instantiate modules.
//!
//! A [`Linker`] performs name-based resolution of the imports of a WebAssembly
//! module so the [`Linker::instantiate`] method does not take an `imports`
//! argument like [`Instance::new`] does. Methods like [`Linker::define`] or
//! [`Linker::func_wrap`] can be used to define names within a [`Linker`] to
//! later be used for instantiation.
//!
//! For example we can reimplement the above example with a `Linker`:
//!
//! ```
//! use wasmtime::*;
//!
//! fn main() -> wasmtime::Result<()> {
//! let engine = Engine::default();
//! let wat = r#"
//! (module
//! (import "host" "host_func" (func $host_hello (param i32)))
//!
//! (func (export "hello")
//! i32.const 3
//! call $host_hello)
//! )
//! "#;
//! let module = Module::new(&engine, wat)?;
//!
//! // Create a `Linker` and define our host function in it:
//! let mut linker = Linker::new(&engine);
//! linker.func_wrap("host", "host_func", |caller: Caller<'_, u32>, param: i32| {
//! println!("Got {} from WebAssembly", param);
//! println!("my host state is: {}", caller.data());
//! })?;
//!
//! // Use the `linker` to instantiate the module, which will automatically
//! // resolve the imports of the module using name-based resolution.
//! let mut store = Store::new(&engine, 0);
//! let instance = linker.instantiate(&mut store, &module)?;
//! let hello = instance.get_typed_func::<(), ()>(&mut store, "hello")?;
//! hello.call(&mut store, ())?;
//!
//! Ok(())
//! }
//! ```
//!
//! The [`Linker`] type also transparently handles Commands and Reactors
//! as defined by WASI.
//!
//! ## 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 entirely isolated
//! from each other, though, we'll be creating a new [`Store`] 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. Finally the last step of initialization would be to create a
//! [`Linker`] which will later be used to instantiate modules, adding
//! functionality like WASI to the linker too.
//!
//! 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`]
//! and [`Linker`] from before you'd then call [`Linker::instantiate`] 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`]
//! is dropped and everything will be deallocated. Note that if the same
//! [`Store`] were used for every request then that would have all requests
//! sharing resources and nothing would ever get deallocated, causing memory
//! usage to baloon and would achive less isolation between requests.
//!
//! ## WASI
//!
//! The `wasmtime` crate does not natively provide support for WASI, but you can
@ -218,36 +176,22 @@
//!
//! [`wasmtime-wasi`]: https://crates.io/crates/wasmtime-wasi
//!
//! ## Cross-store usage of items
//!
//! In `wasmtime` wasm items such as [`Global`] and [`Memory`] "belong" to a
//! [`Store`]. The store they belong to is the one they were created with
//! (passed in as a parameter) or instantiated with. This store is the only
//! store that can be used to interact with wasm items after they're created.
//!
//! The `wasmtime` crate will panic if the [`Store`] argument passed in to these
//! operations is incorrect. In other words it's considered a programmer error
//! rather than a recoverable error for the wrong [`Store`] to be used when
//! calling APIs.
//!
//! ## Crate Features
//!
//! The `wasmtime` crate comes with a number of compile-time features that can
//! be used to customize what features it supports. Some of these features are
//! just internal details, but some affect the public API of the `wasmtime`
//! crate. Be sure to check the API you're using to see if any crate features
//! are enabled.
//! crate. Wasmtime APIs gated behind a Cargo feature should be indicated as
//! such in the documentation.
//!
//! * `runtime` - Enabled by default, this feature enables executing
//! WebAssembly modules. If modules are only compiled, however, this feature
//! can be disabled.
//! WebAssembly modules and components. If a compiler is not available (such
//! as `cranelift`) then [`Module::deserialize`] must be used, for example, to
//! provide an ahead-of-time compiled artifact to execute WebAssembly.
//!
//! * `cranelift` - Enabled by default, this features enables using Cranelift at
//! runtime to compile a WebAssembly module to native code. This feature is
//! required to process and compile new WebAssembly modules. If this feature
//! is disabled then the only way to create a [`Module`] is to use the
//! [`Module::deserialize`] function with a precompiled artifact (typically
//! compiled with the same version of Wasmtime, just somewhere else).
//! required to process and compile new WebAssembly modules and components.
//!
//! * `cache` - Enabled by default, this feature adds support for wasmtime to
//! perform internal caching of modules in a global location. This must still
@ -255,42 +199,31 @@
//! [`Config::cache_config_load_default`].
//!
//! * `wat` - Enabled by default, this feature adds support for accepting the
//! text format of WebAssembly in [`Module::new`]. The text format will be
//! text format of WebAssembly in [`Module::new`] and
//! [`Component::new`](component::Component::new). The text format will be
//! automatically recognized and translated to binary when compiling a
//! module.
//!
//! * `parallel-compilation` - Enabled by default, this feature enables support
//! for compiling functions of a module in parallel with `rayon`.
//! for compiling functions in parallel with `rayon`.
//!
//! * `async` - Enabled by default, this feature enables APIs and runtime
//! support for defining asynchronous host functions and calling WebAssembly
//! asynchronously.
//! asynchronously. For more information see [`Config::async_support`].
//!
//! * `jitdump` - Enabled by default, this feature compiles in support for the
//! jitdump runtime profiling format. The profiler can be selected with
//! [`Config::profiler`].
//!
//! * `vtune` - Enabled by default, this feature compiles in support for VTune
//! profiling of JIT code.
//! * `profiling` - Enabled by default, this feature compiles in support for
//! profiling guest code via a number of possible strategies. See
//! [`Config::profiler`] for more information.
//!
//! * `all-arch` - Not enabled by default. This feature compiles in support for
//! all architectures for both the JIT compiler and the `wasmtime compile` CLI
//! command.
//! command. This can be combined with [`Config::target`] to precompile
//! modules for a different platform than the host.
//!
//! * `pooling-allocator` - Enabled by default, this feature adds support for
//! the pooling allocation strategy enabled via
//! [`Config::allocation_strategy`]. The pooling allocator can enable more
//! efficient reuse of resources for high-concurrency and
//! high-instantiation-count scenarios.
//!
//! * `memory-init-cow` - Enabled by default, this feature builds in support
//! for, on supported platforms, initializing wasm linear memories with
//! copy-on-write heap mappings. This makes instantiation much faster by
//! `mmap`-ing the initial memory image into place instead of copying memory
//! into place, allowing sharing pages that end up only getting read. Note
//! that this is simply compile-time support and this must also be enabled at
//! run-time via [`Config::memory_init_cow`] (which is also enabled by
//! default).
//! [`PoolingAllocationConfig`] to pass to [`Config::allocation_strategy`].
//! The pooling allocator can enable efficient reuse of resources for
//! high-concurrency and high-instantiation-count scenarios.
//!
//! * `demangle` - Enabled by default, this will affect how backtraces are
//! printed and whether symbol names from WebAssembly are attempted to be
@ -310,98 +243,13 @@
//! will enable debugging guest code compiled to WebAssembly. This must also
//! be enabled via [`Config::debug_info`] as well for guests.
//!
//! * `component-model` - Enabled by default, this enables support for the
//! [`wasmtime::component`](component) API for working with components.
//!
//! More crate features can be found in the [manifest] of Wasmtime itself for
//! seeing what can be enabled and disabled.
//!
//! [manifest]: https://github.com/bytecodealliance/wasmtime/blob/main/crates/wasmtime/Cargo.toml
//!
//! ## 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 wasmtime::*;
//! use wasmtime_wasi::sync::WasiCtxBuilder;
//!
//! # fn main() -> wasmtime::Result<()> {
//! // Compile our module and create a `Linker` which has WASI functions defined
//! // within it.
//! let engine = Engine::default();
//! let module = Module::from_file(&engine, "foo.wasm")?;
//! let mut linker = Linker::new(&engine);
//! wasmtime_wasi::add_to_linker(&mut linker, |cx| cx)?;
//!
//! // Configure and create a `WasiCtx`, which WASI functions need access to
//! // through the host state of the store (which in this case is the host state
//! // of the store)
//! let wasi_ctx = WasiCtxBuilder::new().inherit_stdio().build();
//! let mut store = Store::new(&engine, wasi_ctx);
//!
//! // Instantiate our module with the imports we've created, and run it.
//! let instance = linker.instantiate(&mut store, &module)?;
//! // ...
//!
//! # Ok(())
//! # }
//! ```
//!
//! An example of reading a string from a wasm module:
//!
//! ```
//! use std::str;
//!
//! # use wasmtime::*;
//! # fn main() -> wasmtime::Result<()> {
//! let mut store = Store::default();
//! let log_str = Func::wrap(&mut store, |mut caller: Caller<'_, ()>, ptr: i32, len: i32| {
//! // Use our `caller` context to learn about the memory export of the
//! // module which called this host function.
//! let mem = match caller.get_export("memory") {
//! Some(Extern::Memory(mem)) => mem,
//! _ => anyhow::bail!("failed to find host memory"),
//! };
//!
//! // Use the `ptr` and `len` values to get a subslice of the wasm-memory
//! // which we'll attempt to interpret as utf-8.
//! let data = mem.data(&caller)
//! .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(_) => anyhow::bail!("invalid utf-8"),
//! },
//! None => anyhow::bail!("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(&mut store, &module, &[log_str.into()])?;
//! let foo = instance.get_typed_func::<(), ()>(&mut store, "foo")?;
//! foo.call(&mut store, ())?;
//! # Ok(())
//! # }
//! ```
#![deny(missing_docs)]
#![doc(test(attr(deny(warnings))))]
@ -434,6 +282,7 @@ pub use crate::engine::*;
/// This type can be used to interact with `wasmtimes`'s extensive use
/// of `anyhow::Error` while still not directly depending on `anyhow`.
/// This type alias is identical to `anyhow::Result`.
#[doc(no_inline)]
pub use anyhow::{Error, Result};
fn _assert_send_and_sync<T: Send + Sync>() {}

129
crates/wasmtime/src/runtime/component/component.rs

@ -20,8 +20,36 @@ use wasmtime_runtime::{
};
/// A compiled WebAssembly Component.
//
// FIXME: need to write more docs here.
///
/// This structure represents a compiled component that is ready to be
/// instantiated. This owns a region of virtual memory which contains executable
/// code compiled from a WebAssembly binary originally. This is the analog of
/// [`Module`](crate::Module) in the component embedding API.
///
/// A [`Component`] can be turned into an
/// [`Instance`](crate::component::Instance) through a
/// [`Linker`](crate::component::Linker). [`Component`]s are safe to share
/// across threads. The compilation model of a component is the same as that of
/// [a module](crate::Module) which is to say:
///
/// * Compilation happens synchronously during [`Component::new`].
/// * The result of compilation can be saved into storage with
/// [`Component::serialize`].
/// * A previously compiled artifact can be parsed with
/// [`Component::deserialize`].
/// * No compilation happens at runtime for a component — everything is done
/// by the time [`Component::new`] returns.
///
/// ## Components and `Clone`
///
/// Using `clone` on a `Component` is a cheap operation. It will not create an
/// entirely new component, but rather just a new reference to the existing
/// component. In other words it's a shallow copy, not a deep copy.
///
/// ## Examples
///
/// For example usage see the documentation of [`Module`](crate::Module) as
/// [`Component`] has the same high-level API.
#[derive(Clone)]
pub struct Component {
inner: Arc<ComponentInner>,
@ -53,10 +81,64 @@ pub(crate) struct AllCallFuncPointers {
}
impl Component {
/// Compiles a new WebAssembly component from the in-memory wasm image
/// Compiles a new WebAssembly component from the in-memory list of bytes
/// provided.
//
// FIXME: need to write more docs here.
///
/// The `bytes` provided can either be the binary or text format of a
/// [WebAssembly component]. Note that the text format requires the `wat`
/// feature of this crate to be enabled. This API does not support
/// streaming compilation.
///
/// This function will synchronously validate the entire component,
/// including all core modules, and then compile all components, modules,
/// etc., found within the provided bytes.
///
/// [WebAssembly component]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md
///
/// # Errors
///
/// This function may fail and return an error. Errors may include
/// situations such as:
///
/// * The binary provided could not be decoded because it's not a valid
/// WebAssembly binary
/// * The WebAssembly binary may not validate (e.g. contains type errors)
/// * Implementation-specific limits were exceeded with a valid binary (for
/// example too many locals)
/// * The wasm binary may use features that are not enabled in the
/// configuration of `engine`
/// * If the `wat` feature is enabled and the input is text, then it may be
/// rejected if it fails to parse.
///
/// The error returned should contain full information about why compilation
/// failed.
///
/// # Examples
///
/// The `new` function can be invoked with a in-memory array of bytes:
///
/// ```no_run
/// # use wasmtime::*;
/// # use wasmtime::component::Component;
/// # fn main() -> anyhow::Result<()> {
/// # let engine = Engine::default();
/// # let wasm_bytes: Vec<u8> = Vec::new();
/// let component = Component::new(&engine, &wasm_bytes)?;
/// # Ok(())
/// # }
/// ```
///
/// Or you can also pass in a string to be parsed as the wasm text
/// format:
///
/// ```
/// # use wasmtime::*;
/// # use wasmtime::component::Component;
/// # fn main() -> anyhow::Result<()> {
/// # let engine = Engine::default();
/// let component = Component::new(&engine, "(component (core module))")?;
/// # Ok(())
/// # }
#[cfg(any(feature = "cranelift", feature = "winch"))]
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))]
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> {
@ -66,10 +148,11 @@ impl Component {
Component::from_binary(engine, &bytes)
}
/// Compiles a new WebAssembly component from a wasm file on disk pointed to
/// by `file`.
//
// FIXME: need to write more docs here.
/// Compiles a new WebAssembly component from a wasm file on disk pointed
/// to by `file`.
///
/// This is a convenience function for reading the contents of `file` on
/// disk and then calling [`Component::new`].
#[cfg(any(feature = "cranelift", feature = "winch"))]
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))]
pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Component> {
@ -94,8 +177,13 @@ impl Component {
/// Compiles a new WebAssembly component from the in-memory wasm image
/// provided.
//
// FIXME: need to write more docs here.
///
/// This function is the same as [`Component::new`] except that it does not
/// accept the text format of WebAssembly. Even if the `wat` feature
/// is enabled an error will be returned here if `binary` is the text
/// format.
///
/// For more information on semantics and errors see [`Component::new`].
#[cfg(any(feature = "cranelift", feature = "winch"))]
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))]
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Component> {
@ -153,12 +241,17 @@ impl Component {
/// Same as [`Module::deserialize`], but for components.
///
/// Note that the file referenced here must contain contents previously
/// Note that the bytes referenced here must contain contents previously
/// produced by [`Engine::precompile_component`] or
/// [`Component::serialize`].
///
/// For more information see the [`Module::deserialize`] method.
///
/// # Unsafety
///
/// The unsafety of this method is the same as that of the
/// [`Module::deserialize`] method.
///
/// [`Module::deserialize`]: crate::Module::deserialize
pub unsafe fn deserialize(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> {
let code = engine.load_code_bytes(bytes.as_ref(), ObjectKind::Component)?;
@ -167,8 +260,16 @@ impl Component {
/// Same as [`Module::deserialize_file`], but for components.
///
/// For more information see the [`Component::deserialize`] and
/// [`Module::deserialize_file`] methods.
/// Note that the file referenced here must contain contents previously
/// produced by [`Engine::precompile_component`] or
/// [`Component::serialize`].
///
/// For more information see the [`Module::deserialize_file`] method.
///
/// # Unsafety
///
/// The unsafety of this method is the same as that of the
/// [`Module::deserialize_file`] method.
///
/// [`Module::deserialize_file`]: crate::Module::deserialize_file
pub unsafe fn deserialize_file(engine: &Engine, path: impl AsRef<Path>) -> Result<Component> {

77
crates/wasmtime/src/runtime/component/func.rs

@ -85,9 +85,13 @@ union ParamsAndResults<Params: Copy, Return: Copy> {
ret: Return,
}
/// A WebAssembly component function.
//
// FIXME: write more docs here
/// A WebAssembly component function which can be called.
///
/// This type is the dual of [`wasmtime::Func`](crate::Func) for component
/// functions. An instance of [`Func`] represents a component function from a
/// component [`Instance`](crate::component::Instance). Like with
/// [`wasmtime::Func`](crate::Func) it's possible to call functions either
/// synchronously or asynchronously and either typed or untyped.
#[derive(Copy, Clone, Debug)]
pub struct Func(Stored<FuncData>);
@ -150,8 +154,8 @@ impl Func {
/// The `Params` type parameter here is a tuple of the parameters to the
/// function. A function which takes no arguments should use `()`, a
/// function with one argument should use `(T,)`, etc. Note that all
/// `Params` must also implement the [`Lower`] trait since they're going tin
/// to wasm.
/// `Params` must also implement the [`Lower`] trait since they're going
/// into wasm.
///
/// The `Return` type parameter is the return value of this function. A
/// return value of `()` means that there's no return (similar to a Rust
@ -164,6 +168,9 @@ impl Func {
/// primitives, floats, `Option<T>`, `Result<T, E>`, strings, `Vec<T>`, and
/// more. As parameters you'll be passing native Rust types.
///
/// See the documentation for [`ComponentType`] for more information about
/// supported types.
///
/// # Errors
///
/// If the function does not actually take `Params` as its parameters or
@ -284,15 +291,39 @@ impl Func {
/// Invokes this function with the `params` given and returns the result.
///
/// The `params` here must match the type signature of this `Func`, or this will return an error. If a trap
/// occurs while executing this function, then an error will also be returned.
// TODO: say more -- most of the docs for `TypedFunc::call` apply here, too
//
// # Panics
//
// Panics if this is called on a function in an asyncronous store. This only works
// with functions defined within a synchronous store. Also panics if `store`
// does not own this function.
/// The `params` provided must match the parameters that this function takes
/// in terms of their types and the number of parameters. Results will be
/// written to the `results` slice provided if the call completes
/// successfully. The initial types of the values in `results` are ignored
/// and values are overwritten to write the result. It's required that the
/// size of `results` exactly matches the number of results that this
/// function produces.
///
/// Note that after a function is invoked the embedder needs to invoke
/// [`Func::post_return`] to execute any final cleanup required by the
/// guest. This function call is required to either call the function again
/// or to call another function.
///
/// For more detailed information see the documentation of
/// [`TypedFunc::call`].
///
/// # Errors
///
/// Returns an error in situations including but not limited to:
///
/// * `params` is not the right size or if the values have the wrong type
/// * `results` is not the right size
/// * A trap occurs while executing the function
/// * The function calls a host function which returns an error
///
/// See [`TypedFunc::call`] for more information in addition to
/// [`wasmtime::Func::call`](crate::Func::call).
///
/// # Panics
///
/// Panics if this is called on a function in an asyncronous store. This
/// only works with functions defined within a synchronous store. Also
/// panics if `store` does not own this function.
pub fn call(
&self,
mut store: impl AsContextMut,
@ -309,11 +340,14 @@ impl Func {
/// Exactly like [`Self::call`] except for use on async stores.
///
/// Note that after this [`Func::post_return_async`] will be used instead of
/// the synchronous version at [`Func::post_return`].
///
/// # Panics
///
/// Panics if this is called on a function in a synchronous store. This only works
/// with functions defined within an asynchronous store. Also panics if `store`
/// does not own this function.
/// Panics if this is called on a function in a synchronous store. This
/// only works with functions defined within an asynchronous store. Also
/// panics if `store` does not own this function.
#[cfg(feature = "async")]
#[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
pub async fn call_async<T>(
@ -539,11 +573,9 @@ impl Func {
/// Invokes the `post-return` canonical ABI option, if specified, after a
/// [`Func::call`] has finished.
///
/// For some more information on when to use this function see the
/// documentation for post-return in the [`Func::call`] method.
/// Otherwise though this function is a required method call after a
/// [`Func::call`] completes successfully. After the embedder has
/// finished processing the return value then this function must be invoked.
/// This function is a required method call after a [`Func::call`] completes
/// successfully. After the embedder has finished processing the return
/// value then this function must be invoked.
///
/// # Errors
///
@ -598,7 +630,6 @@ impl Func {
store.on_fiber(|store| self.post_return_impl(store)).await?
}
#[inline]
fn post_return_impl(&self, mut store: impl AsContextMut) -> Result<()> {
let mut store = store.as_context_mut();
let data = &mut store.0[self.0];

110
crates/wasmtime/src/runtime/component/func/typed.rs

@ -29,6 +29,8 @@ use wasmtime_runtime::SendSyncPtr;
/// and usage will panic if used with the wrong store.
///
/// This type is primarily created with the [`Func::typed`] API.
///
/// See [`ComponentType`] for more information about supported types.
pub struct TypedFunc<Params, Return> {
func: Func,
@ -365,11 +367,47 @@ pub unsafe trait ComponentNamedList: ComponentType {}
/// with the canonical ABI.
///
/// This trait is implemented for Rust types which can be communicated to
/// components. This is implemented for Rust types which correspond to
/// interface types in the component model of WebAssembly. The [`Func::typed`]
/// and [`TypedFunc`] Rust items are the main consumers of this trait.
///
/// For more information on this trait see the examples in [`Func::typed`].
/// components. The [`Func::typed`] and [`TypedFunc`] Rust items are the main
/// consumers of this trait.
///
/// Supported Rust types include:
///
/// | Component Model Type | Rust Type |
/// |-----------------------------------|--------------------------------------|
/// | `{s,u}{8,16,32,64}` | `{i,u}{8,16,32,64}` |
/// | `f{32,64}` | `f{32,64}` |
/// | `bool` | `bool` |
/// | `char` | `char` |
/// | `tuple<A, B>` | `(A, B)` |
/// | `option<T>` | `Option<T>` |
/// | `result` | `Result<(), ()>` |
/// | `result<T>` | `Result<T, ()>` |
/// | `result<_, E>` | `Result<(), E>` |
/// | `result<T, E>` | `Result<T, E>` |
/// | `string` | `String`, `&str`, or [`WasmStr`] |
/// | `list<T>` | `Vec<T>`, `&[T]`, or [`WasmList`] |
/// | `own<T>`, `borrow<T>` | [`Resource<T>`] or [`ResourceAny`] |
/// | `record` | [`#[derive(ComponentType)]`][d-cm] |
/// | `variant` | [`#[derive(ComponentType)]`][d-cm] |
/// | `enum` | [`#[derive(ComponentType)]`][d-cm] |
/// | `flags` | [`flags!`][f-m] |
///
/// [`Resource<T>`]: crate::component::Resource
/// [`ResourceAny`]: crate::component::ResourceAny
/// [d-cm]: macro@crate::component::ComponentType
/// [f-m]: crate::component::flags
///
/// Rust standard library pointers such as `&T`, `Box<T>`, `Rc<T>`, and `Arc<T>`
/// additionally represent whatever type `T` represents in the component model.
/// Note that types such as `record`, `variant`, `enum`, and `flags` are
/// generated by the embedder at compile time. These macros derive
/// implementation of this trait for custom types to map to custom types in the
/// component model. Note that for `record`, `variant`, `enum`, and `flags`
/// those types are often generated by the
/// [`bindgen!`](crate::component::bindgen) macro from WIT definitions.
///
/// Types that implement [`ComponentType`] are used for `Params` and `Return`
/// in [`TypedFunc`] and [`Func::typed`].
///
/// The contents of this trait are hidden as it's intended to be an
/// implementation detail of Wasmtime. The contents of this trait are not
@ -454,9 +492,18 @@ pub unsafe trait ComponentVariant: ComponentType {
/// either as parameters of component exports or returns of component imports.
/// This trait represents the ability to convert from the native host
/// representation to the canonical ABI.
//
// TODO: #[derive(Lower)]
// TODO: more docs here
///
/// Built-in types to Rust such as `Option<T>` implement this trait as
/// appropriate. For a mapping of component model to Rust types see
/// [`ComponentType`].
///
/// For user-defined types, for example `record` types mapped to Rust `struct`s,
/// this crate additionally has
/// [`#[derive(Lower)]`](macro@crate::component::Lower).
///
/// Note that like [`ComponentType`] the definition of this trait is intended to
/// be an internal implementation detail of Wasmtime at this time. It's
/// recommended to use the `#[derive(Lower)]` implementation instead.
pub unsafe trait Lower: ComponentType {
/// Performs the "lower" function in the canonical ABI.
///
@ -535,9 +582,21 @@ pub unsafe trait Lower: ComponentType {
}
/// Host types which can be created from the canonical ABI.
//
// TODO: #[derive(Lower)]
// TODO: more docs here
///
/// This is the mirror of the [`Lower`] trait where it represents the capability
/// of acquiring items from WebAssembly and passing them to the host.
///
/// Built-in types to Rust such as `Option<T>` implement this trait as
/// appropriate. For a mapping of component model to Rust types see
/// [`ComponentType`].
///
/// For user-defined types, for example `record` types mapped to Rust `struct`s,
/// this crate additionally has
/// [`#[derive(Lift)]`](macro@crate::component::Lift).
///
/// Note that like [`ComponentType`] the definition of this trait is intended to
/// be an internal implementation detail of Wasmtime at this time. It's
/// recommended to use the `#[derive(Lift)]` implementation instead.
pub unsafe trait Lift: Sized + ComponentType {
/// Performs the "lift" operation in the canonical ABI.
///
@ -1178,6 +1237,23 @@ fn lower_string<T>(cx: &mut LowerContext<'_, T>, string: &str) -> Result<(usize,
/// Representation of a string located in linear memory in a WebAssembly
/// instance.
///
/// This type can be used in place of `String` and `str` for string-taking APIs
/// in some situations. The purpose of this type is to represent a range of
/// validated bytes within a component but does not actually copy the bytes. The
/// primary method, [`WasmStr::to_str`], attempts to return a reference to the
/// string directly located in the component's memory, avoiding a copy into the
/// host if possible.
///
/// The downside of this type, however, is that accessing a string requires a
/// [`Store`](crate::Store) pointer (via [`StoreContext`]). Bindings generated
/// by [`bindgen!`](crate::component::bindgen), for example, do not have access
/// to [`StoreContext`] and thus can't use this type.
///
/// This is intended for more advanced use cases such as defining functions
/// directly in a [`Linker`](crate::component::Linker). It's expected that in
/// the future [`bindgen!`](crate::component::bindgen) will also have a way to
/// use this type.
///
/// This type is used with [`TypedFunc`], for example, when WebAssembly returns
/// a string. This type cannot be used to give a string to WebAssembly, instead
/// `&str` should be used for that (since it's coming from the host).
@ -1185,8 +1261,9 @@ fn lower_string<T>(cx: &mut LowerContext<'_, T>, string: &str) -> Result<(usize,
/// Note that this type represents an in-bounds string in linear memory, but it
/// does not represent a valid string (e.g. valid utf-8). Validation happens
/// when [`WasmStr::to_str`] is called.
//
// TODO: should probably expand this with examples
///
/// Also note that this type does not implement [`Lower`], it only implements
/// [`Lift`].
pub struct WasmStr {
ptr: usize,
len: usize,
@ -1414,6 +1491,11 @@ where
/// Representation of a list of values that are owned by a WebAssembly instance.
///
/// For some more commentary about the rationale for this type see the
/// documentation of [`WasmStr`]. In summary this type can avoid a copy when
/// passing data to the host in some situations but is additionally more
/// cumbersome to use by requiring a [`Store`](crate::Store) to be provided.
///
/// This type is used whenever a `(list T)` is returned from a [`TypedFunc`],
/// for example. This type represents a list of values that are stored in linear
/// memory which are waiting to be read.
@ -1421,6 +1503,8 @@ where
/// Note that this type represents only a valid range of bytes for the list
/// itself, it does not represent validity of the elements themselves and that's
/// performed when they're iterated.
///
/// Note that this type does not implement the [`Lower`] trait, only [`Lift`].
pub struct WasmList<T> {
ptr: usize,
len: usize,

17
crates/wasmtime/src/runtime/component/instance.rs

@ -19,11 +19,18 @@ use wasmtime_runtime::VMFuncRef;
/// An instantiated component.
///
/// This is similar to [`crate::Instance`] except that it represents an
/// instantiated component instead of an instantiated module. Otherwise though
/// the two behave similarly.
//
// FIXME: need to write more docs here.
/// This type represents an instantiated [`Component`](super::Component).
/// Instances have exports which can be accessed through functions such as
/// [`Instance::get_func`] or [`Instance::exports`]. Instances are owned by a
/// [`Store`](crate::Store) and all methods require a handle to the store.
///
/// Component instances are created through
/// [`Linker::instantiate`](super::Linker::instantiate) and its family of
/// methods.
///
/// This type is similar to the core wasm version
/// [`wasmtime::Instance`](crate::Instance) except that it represents an
/// instantiated component instead of an instantiated module.
#[derive(Copy, Clone)]
pub struct Instance(pub(crate) Stored<Option<Box<InstanceData>>>);

377
crates/wasmtime/src/runtime/component/mod.rs

@ -1,7 +1,43 @@
//! In-progress implementation of the WebAssembly component model
//! # Embedding API for the Component Model
//!
//! This module is a work-in-progress and currently represents an incomplete and
//! probably buggy implementation of the component model.
//! This module contains the embedding API for the [Component Model] in
//! Wasmtime. This module requires the `component-model` feature to be enabled,
//! which is enabled by default. The embedding API here is mirrored after the
//! core wasm embedding API at the crate root and is intended to have the same
//! look-and-feel while handling concepts of the component model.
//!
//! [Component Model]: https://component-model.bytecodealliance.org
//!
//! The component model is a broad topic which can't be explained here fully, so
//! it's recommended to read over individual items' documentation to see more
//! about the capabilities of the embedding API. At a high-level, however,
//! perhaps the most interesting items in this module are:
//!
//! * [`Component`] - a compiled component ready to be instantiated. Similar to
//! a [`Module`](crate::Module) for core wasm.
//!
//! * [`Linker`] - a component-style location for defining host functions. This
//! is not the same as [`wasmtime::Linker`](crate::Linker) for core wasm
//! modules.
//!
//! * [`bindgen!`] - a macro to generate Rust bindings for a [WIT] [world]. This
//! maps all WIT types into Rust automatically and generates traits for
//! embedders to implement.
//!
//! [WIT]: https://component-model.bytecodealliance.org/design/wit.html
//! [world]: https://component-model.bytecodealliance.org/design/worlds.html
//!
//! Embedders of the component model will typically start by defining their API
//! in [WIT]. This describes what will be available to guests and what needs to
//! be provided to the embedder by the guest. This [`world`][world] that was
//! created is then fed into [`bindgen!`] to generate types and traits for the
//! embedder to use. The embedder then implements these traits, adds
//! functionality via the generated `add_to_linker` method (see [`bindgen!`] for
//! more info), and then instantiates/executes a component.
//!
//! It's recommended to read over the [documentation for the Component
//! Model][Component Model] to get an overview about how to build components
//! from various languages.
#![cfg_attr(nightlydoc, doc(cfg(feature = "component-model")))]
@ -26,7 +62,6 @@ pub use self::resource_table::{ResourceTable, ResourceTableError};
pub use self::resources::{Resource, ResourceAny};
pub use self::types::{ResourceType, Type};
pub use self::values::{Enum, Flags, List, OptionVal, Record, ResultVal, Tuple, Val, Variant};
pub use wasmtime_component_macro::{flags, ComponentType, Lift, Lower};
// These items are expected to be used by an eventual
// `#[derive(ComponentType)]`, they are not part of Wasmtime's API stability
@ -50,26 +85,26 @@ pub mod __internal {
pub(crate) use self::store::ComponentStoreData;
/// Generate bindings for a WIT package.
/// Generate bindings for a [WIT world].
///
/// [WIT world]: https://component-model.bytecodealliance.org/design/worlds.html
/// [WIT package]: https://component-model.bytecodealliance.org/design/packages.html
///
/// This macro ingests a [WIT package] and will generate all the necessary
/// bindings for instantiating and invoking a particular `world` in the
/// package. A `world` in a WIT package is a description of imports and exports
/// for a component. This provides a higher-level representation of working with
/// a component than the raw [`Instance`] type which must be manually-type-check
/// and manually have its imports provided via the [`Linker`] type.
/// This macro ingests a [WIT world] and will generate all the necessary
/// bindings for instantiating components that ascribe to the `world`. This
/// provides a higher-level representation of working with a component than the
/// raw [`Instance`] type which must be manually-type-checked and manually have
/// its imports provided via the [`Linker`] type.
///
/// The most basic usage of this macro is:
///
/// ```rust,ignore
/// wasmtime::component::bindgen!("my-component");
/// wasmtime::component::bindgen!();
/// ```
///
/// This will parse your projects WIT package in a `wit` directory adjacent to
/// This will parse your projects [WIT package] in a `wit` directory adjacent to
/// your crate's `Cargo.toml`. All of the `*.wit` files in that directory are
/// parsed and then the `default world` will be looked up within
/// `my-component.wit`. This world is then used as the basis for generating
/// bindings.
/// parsed and then the single `world` found will be used for bindings.
///
/// For example if your project contained:
///
@ -86,18 +121,29 @@ pub(crate) use self::store::ComponentStoreData;
///
/// Then you can interact with the generated bindings like so:
///
/// ```rust,ignore
/// ```rust
/// use wasmtime::component::*;
/// use wasmtime::{Config, Engine, Store};
///
/// # const _: () = { macro_rules! bindgen { () => () }
/// bindgen!();
/// # };
/// # bindgen!({
/// # inline: r#"
/// # package my:project;
/// # world hello-world {
/// # import name: func() -> string;
/// # export greet: func();
/// # }
/// # "#,
/// # });
///
/// struct MyState {
/// name: String,
/// }
///
/// // Imports into the world, like the `name` import for this world, are satisfied
/// // through traits.
/// // Imports into the world, like the `name` import for this world, are
/// // satisfied through traits.
/// impl HelloWorldImports for MyState {
/// // Note the `Result` return value here where `Ok` is returned back to
/// // the component and `Err` will raise a trap.
@ -107,6 +153,7 @@ pub(crate) use self::store::ComponentStoreData;
/// }
///
/// fn main() -> wasmtime::Result<()> {
/// # if true { return Ok(()) }
/// // Configure an `Engine` and compile the `Component` that is being run for
/// // the application.
/// let mut config = Config::new();
@ -162,7 +209,7 @@ pub(crate) use self::store::ComponentStoreData;
/// sha256: func(bytes: list<u8>) -> string;
/// }
///
/// default world hello-world {
/// world hello-world {
/// import host;
///
/// export demo: interface {
@ -173,12 +220,32 @@ pub(crate) use self::store::ComponentStoreData;
///
/// Then you can interact with the generated bindings like so:
///
/// ```rust,ignore
/// ```rust
/// use wasmtime::component::*;
/// use wasmtime::{Config, Engine, Store};
/// use my::project::host::Host;
///
/// # const _: () = { macro_rules! bindgen { () => () }
/// bindgen!();
/// # };
/// # bindgen!({
/// # inline: r#"
/// # package my:project;
/// #
/// # interface host {
/// # gen-random-integer: func() -> u32;
/// # sha256: func(bytes: list<u8>) -> string;
/// # }
/// #
/// # world hello-world {
/// # import host;
/// #
/// # export demo: interface {
/// # run: func();
/// # }
/// # }
/// # "#,
/// # });
///
/// struct MyState {
/// // ...
@ -187,15 +254,19 @@ pub(crate) use self::store::ComponentStoreData;
/// // Note that the trait here is per-interface and within a submodule now.
/// impl Host for MyState {
/// fn gen_random_integer(&mut self) -> wasmtime::Result<u32> {
/// # panic!();
/// # #[cfg(FALSE)]
/// Ok(rand::thread_rng().gen())
/// }
///
/// fn sha256(&mut self, bytes: Vec<u8>) -> wasmtime::Result<String> {
/// // ...
/// # panic!()
/// }
/// }
///
/// fn main() -> wasmtime::Result<()> {
/// # if true { return Ok(()) }
/// let mut config = Config::new();
/// config.wasm_component_model(true);
/// let engine = Engine::new(&config)?;
@ -227,12 +298,12 @@ pub(crate) use self::store::ComponentStoreData;
/// `world` from the parsed package. There are then codegen-specific options to
/// the bindings themselves which can additionally be specified.
///
/// Basic usage of this macro looks like:
/// Usage of this macro looks like:
///
/// ```rust,ignore
/// // Parse the `wit/` folder adjacent to this crate's `Cargo.toml` and look
/// // for a `default world` in its documents. There must be exactly one
/// // `default world` for this to succeed.
/// // for a single `world` in it. There must be exactly one for this to
/// // succeed.
/// bindgen!();
///
/// // Parse the `wit/` folder adjacent to this crate's `Cargo.toml` and look
@ -346,6 +417,260 @@ pub(crate) use self::store::ComponentStoreData;
/// },
/// });
/// ```
///
/// [WIT package]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md
pub use wasmtime_component_macro::bindgen;
/// Derive macro to generate implementations of the [`ComponentType`] trait.
///
/// This derive macro can be applied to `struct` and `enum` definitions and is
/// used to bind either a `record`, `enum`, or `variant` in the component model.
///
/// Note you might be looking for [`bindgen!`] rather than this macro as that
/// will generate the entire type for you rather than just a trait
/// implementation.
///
/// This macro supports a `#[component]` attribute which is used to customize
/// how the type is bound to the component model. A top-level `#[component]`
/// attribute is required to specify either `record`, `enum`, or `variant`.
///
/// ## Records
///
/// `record`s in the component model correspond to `struct`s in Rust. An example
/// is:
///
/// ```rust
/// use wasmtime::component::ComponentType;
///
/// #[derive(ComponentType)]
/// #[component(record)]
/// struct Color {
/// r: u8,
/// g: u8,
/// b: u8,
/// }
/// ```
///
/// which corresponds to the WIT type:
///
/// ```wit
/// record color {
/// r: u8,
/// g: u8,
/// b: u8,
/// }
/// ```
///
/// Note that the name `Color` here does not need to match the name in WIT.
/// That's purely used as a name in Rust of what to refer to. The field names
/// must match that in WIT, however. Field names can be customized with the
/// `#[component]` attribute though.
///
/// ```rust
/// use wasmtime::component::ComponentType;
///
/// #[derive(ComponentType)]
/// #[component(record)]
/// struct VerboseColor {
/// #[component(name = "r")]
/// red: u8,
/// #[component(name = "g")]
/// green: u8,
/// #[component(name = "b")]
/// blue: u8,
/// }
/// ```
///
/// Also note that field ordering is significant at this time and must match
/// WIT.
///
/// ## Variants
///
/// `variant`s in the component model correspond to a subset of shapes of a Rust
/// `enum`. Variants in the component model have a single optional payload type
/// which means that not all Rust `enum`s correspond to component model
/// `variant`s. An example variant is:
///
/// ```rust
/// use wasmtime::component::ComponentType;
///
/// #[derive(ComponentType)]
/// #[component(variant)]
/// enum Filter {
/// #[component(name = "none")]
/// None,
/// #[component(name = "all")]
/// All,
/// #[component(name = "some")]
/// Some(Vec<String>),
/// }
/// ```
///
/// which corresponds to the WIT type:
///
/// ```wit
/// variant filter {
/// none,
/// all,
/// some(list<string>),
/// }
/// ```
///
/// The `variant` style of derive allows an optional payload on Rust `enum`
/// variants but it must be a single unnamed field. Variants of the form `Foo(T,
/// U)` or `Foo { name: T }` are not supported at this time.
///
/// Note that the order of variants in Rust must match the order of variants in
/// WIT. Additionally it's likely that `#[component(name = "...")]` is required
/// on all Rust `enum` variants because the name currently defaults to the Rust
/// name which is typically UpperCamelCase whereas WIT uses kebab-case.
///
/// ## Enums
///
/// `enum`s in the component model correspond to C-like `enum`s in Rust. Note
/// that a component model `enum` does not allow any payloads so the Rust `enum`
/// must additionally have no payloads.
///
/// ```rust
/// use wasmtime::component::ComponentType;
///
/// #[derive(ComponentType)]
/// #[component(enum)]
/// enum Setting {
/// #[component(name = "yes")]
/// Yes,
/// #[component(name = "no")]
/// No,
/// #[component(name = "auto")]
/// Auto,
/// }
/// ```
///
/// which corresponds to the WIT type:
///
/// ```wit
/// enum setting {
/// yes,
/// no,
/// auto,
/// }
/// ```
///
/// Note that the order of variants in Rust must match the order of variants in
/// WIT. Additionally it's likely that `#[component(name = "...")]` is required
/// on all Rust `enum` variants because the name currently defaults to the Rust
/// name which is typically UpperCamelCase whereas WIT uses kebab-case.
pub use wasmtime_component_macro::ComponentType;
/// A derive macro for generating implementations of the [`Lift`] trait.
///
/// This macro will likely be applied in conjunction with the
/// [`#[derive(ComponentType)]`](macro@ComponentType) macro along the lines
/// of `#[derive(ComponentType, Lift)]`. This trait enables reading values from
/// WebAssembly.
///
/// Note you might be looking for [`bindgen!`] rather than this macro as that
/// will generate the entire type for you rather than just a trait
/// implementation.
///
/// At this time this derive macro has no configuration.
///
/// ## Examples
///
/// ```rust
/// use wasmtime::component::{ComponentType, Lift};
///
/// #[derive(ComponentType, Lift)]
/// #[component(record)]
/// struct Color {
/// r: u8,
/// g: u8,
/// b: u8,
/// }
/// ```
pub use wasmtime_component_macro::Lift;
/// A derive macro for generating implementations of the [`Lower`] trait.
///
/// This macro will likely be applied in conjunction with the
/// [`#[derive(ComponentType)]`](macro@ComponentType) macro along the lines
/// of `#[derive(ComponentType, Lower)]`. This trait enables passing values to
/// WebAssembly.
///
/// Note you might be looking for [`bindgen!`] rather than this macro as that
/// will generate the entire type for you rather than just a trait
/// implementation.
///
/// At this time this derive macro has no configuration.
///
/// ## Examples
///
/// ```rust
/// use wasmtime::component::{ComponentType, Lower};
///
/// #[derive(ComponentType, Lower)]
/// #[component(record)]
/// struct Color {
/// r: u8,
/// g: u8,
/// b: u8,
/// }
/// ```
pub use wasmtime_component_macro::Lower;
/// A macro to generate a Rust type corresponding to WIT `flags`
///
/// This macro generates a type that implements the [`ComponentType`], [`Lift`],
/// and [`Lower`] traits. The generated Rust type corresponds to the `flags`
/// type in WIT.
///
/// Example usage of this looks like:
///
/// ```rust
/// use wasmtime::component::flags;
///
/// flags! {
/// Permissions {
/// #[component(name = "read")]
/// const READ;
/// #[component(name = "write")]
/// const WRITE;
/// #[component(name = "execute")]
/// const EXECUTE;
/// }
/// }
///
/// fn validate_permissions(permissions: &mut Permissions) {
/// if permissions.contains(Permissions::EXECUTE | Permissions::WRITE) {
/// panic!("cannot enable both writable and executable at the same time");
/// }
///
/// if permissions.contains(Permissions::READ) {
/// panic!("permissions must at least contain read");
/// }
/// }
/// ```
///
/// which corresponds to the WIT type:
///
/// ```wit
/// flags permissions {
/// read,
/// write,
/// execute,
/// }
/// ```
///
/// This generates a structure which is similar to/inspired by the [`bitflags`
/// crate](https://crates.io/crates/bitflags). The `Permissions` structure
/// generated implements the [`PartialEq`], [`Eq`], [`Debug`], [`BitOr`],
/// [`BitOrAssign`], [`BitAnd`], [`BitAndAssign`], [`BitXor`], [`BitXorAssign`],
/// and [`Not`] traits - in addition to the Wasmtime-specific component ones
/// [`ComponentType`], [`Lift`], and [`Lower`].
///
/// [`BitOr`]: std::ops::BitOr
/// [`BitOrAssign`]: std::ops::BitOrAssign
/// [`BitAnd`]: std::ops::BitAnd
/// [`BitAndAssign`]: std::ops::BitAndAssign
/// [`BitXor`]: std::ops::BitXor
/// [`BitXorAssign`]: std::ops::BitXorAssign
/// [`Not`]: std::ops::Not
pub use wasmtime_component_macro::flags;

150
crates/wasmtime/src/runtime/component/values.rs

@ -13,7 +13,14 @@ use wasmtime_environ::component::{
CanonicalAbiInfo, ComponentTypes, InterfaceType, TypeListIndex, VariantInfo,
};
/// Represents runtime list values
/// Dynamic representation of `list<T>` in the component model.
///
/// This structure is part of the dynamically-typed [`Val`] which represents
/// all possible values in the component model. This is often used in
/// conjunction with [`Func::call`](crate::component::Func::call).
///
/// Note that `Vec<T>` is also supported for component model lists when
/// using [`TypedFunc`](crate::component::TypedFunc).
#[derive(PartialEq, Eq, Clone)]
pub struct List {
ty: types::List,
@ -21,7 +28,12 @@ pub struct List {
}
impl List {
/// Instantiate the specified type with the specified `values`.
/// Creates a new list with the specified type with the specified `values`.
///
/// # Errors
///
/// Returns an error if any value in `values` does not have the element
/// type of `ty` specified.
pub fn new(ty: &types::List, values: Box<[Val]>) -> Result<Self> {
let element_type = ty.ty();
for (index, value) in values.iter().enumerate() {
@ -60,7 +72,15 @@ impl fmt::Debug for List {
}
}
/// Represents runtime record values
/// Dynamic representation of `record` in the component model.
///
/// This structure is part of the dynamically-typed [`Val`] which represents
/// all possible values in the component model. This is often used in
/// conjunction with [`Func::call`](crate::component::Func::call).
///
/// Note that records can also be mapped to Rust `struct`s through the
/// [`#[derive(ComponentType)]`](macro@crate::component::ComponentType) macro
/// and using [`TypedFunc`](crate::component::TypedFunc).
#[derive(PartialEq, Eq, Clone)]
pub struct Record {
ty: types::Record,
@ -68,7 +88,15 @@ pub struct Record {
}
impl Record {
/// Instantiate the specified type with the specified `values`.
/// Creates a new record with the specified `ty` and the `values` for fields.
///
/// Note that the `values` specified for fields must list fields in the
/// same order that the `ty` lists them in.
///
/// # Errors
///
/// Returns an error if any of the `values` specified are in the wrong order
/// field-wise or have the wrong type relative to what's specified in `ty`.
pub fn new<'a>(
ty: &types::Record,
values: impl IntoIterator<Item = (&'a str, Val)>,
@ -111,8 +139,9 @@ impl Record {
&self.ty
}
/// Gets the value of the specified field `name` from this record.
pub fn fields(&self) -> impl Iterator<Item = (&str, &Val)> {
/// Returns the list of fields that this struct contains with their name
/// and value.
pub fn fields(&self) -> impl ExactSizeIterator<Item = (&str, &Val)> {
assert_eq!(self.values.len(), self.ty.fields().len());
self.ty
.fields()
@ -131,7 +160,14 @@ impl fmt::Debug for Record {
}
}
/// Represents runtime tuple values
/// Dynamic representation of `tuple<...>` in the component model.
///
/// This structure is part of the dynamically-typed [`Val`] which represents
/// all possible values in the component model. This is often used in
/// conjunction with [`Func::call`](crate::component::Func::call).
///
/// Note that tuples are also mapped to Rust tuples when using
/// [`TypedFunc`](crate::component::TypedFunc).
#[derive(PartialEq, Eq, Clone)]
pub struct Tuple {
ty: types::Tuple,
@ -139,7 +175,13 @@ pub struct Tuple {
}
impl Tuple {
/// Instantiate the specified type ith the specified `values`.
/// Creates a new tuple with the `ty` specified and `values` for each
/// entry.
///
/// # Errors
///
/// Returns an error if `values` does not match the `ty` specified, such as
/// if it has the wrong length or if any field has the wrong type.
pub fn new(ty: &types::Tuple, values: Box<[Val]>) -> Result<Self> {
if values.len() != ty.types().len() {
bail!(
@ -181,7 +223,15 @@ impl fmt::Debug for Tuple {
}
}
/// Represents runtime variant values
/// Dynamic representation of `variant` in the component model.
///
/// This structure is part of the dynamically-typed [`Val`] which represents
/// all possible values in the component model. This is often used in
/// conjunction with [`Func::call`](crate::component::Func::call).
///
/// Note that variants can also be mapped to Rust `enum`s through the
/// [`#[derive(ComponentType)]`](macro@crate::component::ComponentType) macro
/// and using [`TypedFunc`](crate::component::TypedFunc).
#[derive(PartialEq, Eq, Clone)]
pub struct Variant {
ty: types::Variant,
@ -190,7 +240,18 @@ pub struct Variant {
}
impl Variant {
/// Instantiate the specified type with the specified case `name` and `value`.
/// Creates a new variant with the specified `ty` and the case `name` and
/// `value` provided.
///
/// This will create a instance of a variant with the case `name` which has
/// the optional payload of `value`.
///
/// # Errors
///
/// Returns an error if `name` doesn't match any case of `ty` or if
/// `value` is of the wrong type. Note that `ty` must match the payload
/// type exactly, in that if the case for `name` doesn't have a type then
/// `value` must be `None`.
pub fn new(ty: &types::Variant, name: &str, value: Option<Val>) -> Result<Self> {
let (discriminant, case_type) = ty
.cases()
@ -272,7 +333,15 @@ impl fmt::Debug for Variant {
}
}
/// Represents runtime enum values
/// Dynamic representation of `enum` in the component model.
///
/// This structure is part of the dynamically-typed [`Val`] which represents
/// all possible values in the component model. This is often used in
/// conjunction with [`Func::call`](crate::component::Func::call).
///
/// Note that enums can also be mapped to Rust `enum`s through the
/// [`#[derive(ComponentType)]`](macro@crate::component::ComponentType) macro
/// and using [`TypedFunc`](crate::component::TypedFunc).
#[derive(PartialEq, Eq, Clone)]
pub struct Enum {
ty: types::Enum,
@ -280,7 +349,12 @@ pub struct Enum {
}
impl Enum {
/// Instantiate the specified type with the specified case `name`.
/// Creates a new enum value with the `ty` specified selecting the
/// specified variant called `name`.
///
/// # Errors
///
/// Returns an error if `name` isn't listed within `ty`.
pub fn new(ty: &types::Enum, name: &str) -> Result<Self> {
let discriminant = u32::try_from(
ty.names()
@ -328,7 +402,14 @@ impl fmt::Debug for Enum {
}
}
/// Represents runtime option values
/// Dynamic representation of `option<T>` in the component model.
///
/// This structure is part of the dynamically-typed [`Val`] which represents
/// all possible values in the component model. This is often used in
/// conjunction with [`Func::call`](crate::component::Func::call).
///
/// Note that options are also mapped to Rust `Option<T>` when using
/// [`TypedFunc`](crate::component::TypedFunc).
#[derive(PartialEq, Eq, Clone)]
pub struct OptionVal {
ty: types::OptionType,
@ -337,7 +418,12 @@ pub struct OptionVal {
}
impl OptionVal {
/// Instantiate the specified type with the specified `value`.
/// Creates a new value with the `ty` specified holding the payload `value`.
///
/// # Errors
///
/// Returns an error if `value` is `Some` and the payload has the wrong
/// type for `ty`.
pub fn new(ty: &types::OptionType, value: Option<Val>) -> Result<Self> {
let value = value
.map(|value| {
@ -390,7 +476,14 @@ impl fmt::Debug for OptionVal {
}
}
/// Represents runtime result values
/// Dynamic representation of `result<T, E>` in the component model.
///
/// This structure is part of the dynamically-typed [`Val`] which represents
/// all possible values in the component model. This is often used in
/// conjunction with [`Func::call`](crate::component::Func::call).
///
/// Note that tuples are also mapped to Rust's `Result<T, E>` when using
/// [`TypedFunc`](crate::component::TypedFunc).
#[derive(PartialEq, Eq, Clone)]
pub struct ResultVal {
ty: types::ResultType,
@ -399,7 +492,14 @@ pub struct ResultVal {
}
impl ResultVal {
/// Instantiate the specified type with the specified `value`.
/// Creates a new `Result` from the specified `ty` and `value`.
///
/// Note that the `value` uses `Option<Val>` for payloads to map to the
/// optional payload value of the component model within each variant.
///
/// # Errors
///
/// Returns an error if the `value` payload has the wrong type for `ty`.
pub fn new(ty: &types::ResultType, value: Result<Option<Val>, Option<Val>>) -> Result<Self> {
Ok(Self {
ty: ty.clone(),
@ -459,7 +559,15 @@ impl fmt::Debug for ResultVal {
}
}
/// Represents runtime flag values
/// Dynamic representation of `flags` in the component model.
///
/// This structure is part of the dynamically-typed [`Val`] which represents
/// all possible values in the component model. This is often used in
/// conjunction with [`Func::call`](crate::component::Func::call).
///
/// Note that flags can also be mapped to Rust structures through the
/// [`flags!`](crate::component::flags) macro and using
/// [`TypedFunc`](crate::component::TypedFunc).
#[derive(PartialEq, Eq, Clone)]
pub struct Flags {
ty: types::Flags,
@ -468,7 +576,13 @@ pub struct Flags {
}
impl Flags {
/// Instantiate the specified type with the specified flag `names`.
/// Creates a new set of flags with the `ty` specified and the `names` as
/// members of the flags.
///
/// # Errors
///
/// An error is returned if any of `names` aren't present within the `ty`
/// specified.
pub fn new(ty: &types::Flags, names: &[&str]) -> Result<Self> {
let map = ty
.names()

19
crates/wasmtime/src/runtime/func.rs

@ -18,16 +18,15 @@ use wasmtime_runtime::{
/// A WebAssembly function which can be called.
///
/// This type can represent either an exported function from a WebAssembly
/// module or a host-defined function which can be used to satisfy an import of
/// a module. [`Func`] and can be used to both instantiate an [`Instance`] as
/// well as be extracted from an [`Instance`].
///
/// [`Instance`]: crate::Instance
///
/// A [`Func`] "belongs" to the store that it was originally created within.
/// Operations on a [`Func`] only work with the store it belongs to, and if
/// another store is passed in by accident then methods will panic.
/// This type typically represents an exported function from a WebAssembly
/// module instance. In this case a [`Func`] belongs to an [`Instance`] and is
/// loaded from there. A [`Func`] may also represent a host function as well in
/// some cases, too.
///
/// Functions can be called in a few different ways, either synchronous or async
/// and either typed or untyped (more on this below). Note that host functions
/// are normally inserted directly into a [`Linker`](crate::Linker) rather than
/// using this directly, but both options are available.
///
/// # `Func` and `async`
///

51
crates/wasmtime/src/runtime/module.rs

@ -40,14 +40,25 @@ pub use registry::{
/// representation. Instead you'll need to create an
/// [`Instance`](crate::Instance) to interact with the wasm module.
///
/// Creating a `Module` currently involves compiling code, meaning that it can
/// be an expensive operation. All `Module` instances are compiled according to
/// the configuration in [`Config`], but typically they're JIT-compiled. If
/// you'd like to instantiate a module multiple times you can do so with
/// compiling the original wasm module only once with a single [`Module`]
/// instance.
///
/// The `Module` is thread-safe and safe to share across threads.
/// A `Module` can be created by compiling WebAssembly code through APIs such as
/// [`Module::new`]. This would be a JIT-style use case where code is compiled
/// just before it's used. Alternatively a `Module` can be compiled in one
/// process and [`Module::serialize`] can be used to save it to storage. A later
/// call to [`Module::deserialize`] will quickly load the module to execute and
/// does not need to compile any code, representing a more AOT-style use case.
///
/// Currently a `Module` does not implement any form of tiering or dynamic
/// optimization of compiled code. Creation of a `Module` via [`Module::new`] or
/// related APIs will perform the entire compilation step synchronously. When
/// finished no further compilation will happen at runtime or later during
/// execution of WebAssembly instances for example.
///
/// Compilation of WebAssembly by default goes through Cranelift and is
/// recommended to be done once-per-module. The same WebAssembly binary need not
/// be compiled multiple times and can instead used an embedder-cached result of
/// the first call.
///
/// `Module` is thread-safe and safe to share across threads.
///
/// ## Modules and `Clone`
///
@ -98,6 +109,25 @@ pub use registry::{
/// # }
/// ```
///
/// Serializing and deserializing a module looks like:
///
/// ```no_run
/// # use wasmtime::*;
/// # fn main() -> anyhow::Result<()> {
/// let engine = Engine::default();
/// # let wasm_bytes: Vec<u8> = Vec::new();
/// let module = Module::new(&engine, &wasm_bytes)?;
/// let module_bytes = module.serialize()?;
///
/// // ... can save `module_bytes` to disk or other storage ...
///
/// // recreate the module from the serialized bytes. For the `unsafe` bits
/// // see the documentation of `deserialize`.
/// let module = unsafe { Module::deserialize(&engine, &module_bytes)? };
/// # Ok(())
/// # }
/// ```
///
/// [`Config`]: crate::Config
#[derive(Clone)]
pub struct Module {
@ -157,9 +187,8 @@ impl Module {
/// loaded into memory all at once, this API does not support streaming
/// compilation of a module.
///
/// If the module has not been already been compiled, the WebAssembly binary will
/// be decoded and validated. It will also be compiled according to the
/// configuration of the provided `engine`.
/// The WebAssembly binary will be decoded and validated. It will also be
/// compiled according to the configuration of the provided `engine`.
///
/// # Errors
///

16
crates/wasmtime/src/runtime/store.rs

@ -120,8 +120,8 @@ use func_refs::FuncRefs;
/// [`Store`] it will not be deallocated until the [`Store`] itself is dropped.
/// This makes [`Store`] unsuitable for creating an unbounded number of
/// instances in it because [`Store`] will never release this memory. It's
/// recommended to have a [`Store`] correspond roughly to the lifetime of a "main
/// instance" that an embedding is interested in executing.
/// recommended to have a [`Store`] correspond roughly to the lifetime of a
/// "main instance" that an embedding is interested in executing.
///
/// ## Type parameter `T`
///
@ -158,6 +158,18 @@ use func_refs::FuncRefs;
/// You can create a store with default configuration settings using
/// `Store::default()`. This will create a brand new [`Engine`] with default
/// configuration (see [`Config`](crate::Config) for more information).
///
/// ## Cross-store usage of items
///
/// In `wasmtime` wasm items such as [`Global`] and [`Memory`] "belong" to a
/// [`Store`]. The store they belong to is the one they were created with
/// (passed in as a parameter) or instantiated with. This store is the only
/// store that can be used to interact with wasm items after they're created.
///
/// The `wasmtime` crate will panic if the [`Store`] argument passed in to these
/// operations is incorrect. In other words it's considered a programmer error
/// rather than a recoverable error for the wrong [`Store`] to be used when
/// calling APIs.
pub struct Store<T> {
// for comments about `ManuallyDrop`, see `Store::into_data`
inner: ManuallyDrop<Box<StoreInner<T>>>,

Loading…
Cancel
Save