wasmtime/runtime/component/bindgen_examples/
mod.rs

1//! Examples of output of the [`bindgen!`] macro.
2//!
3//! This module is only included in docs.rs documentation and is not present in
4//! the actual crate when compiling from crates.io. The purpose of this module
5//! is to showcase what the output of the [`bindgen!`] macro looks like and some
6//! examples of how to use it.
7//!
8//! If you're confused or lost in [`bindgen!`] feel free to [open an issue]
9//! with a description of your issue and it can hopefully lead to a new example
10//! being added here for others to use as reference.
11//!
12//! ## Including `*.wit` files in your project
13//!
14//! Note that most of the examples in this module will use the `inline` key of
15//! the [`bindgen!`] macro. This is done as it's easy to show the example and
16//! WIT all in one self-contained snippet of Rust code. Typically though a
17//! project will have a `wit` directory next to `Cargo.toml` which contains WIT
18//! files.
19//!
20//! The general layout of a `wit` directory is that:
21//!
22//! * All `*.wit` files at `wit/*.wit` are parsed and included in the same
23//!   package.
24//! * If the `wit/deps` folder is present then it can either contain:
25//!   * Subdirectories with a package-per-directory. For example
26//!     `wit/deps/wasi-http` and `wit/deps/wasi-cli`.
27//!   * WIT files that are a single-file rendering of a package, for example
28//!     `wit/deps/wasi-http.wit`
29//!   * WIT packages encoded as WebAssembly binaries for a package, for example
30//!     `wit/deps/wasi-http.wasm`
31//!
32//! This means that at this time you'll need to copy around `*.wit` files or
33//! WIT packages encoded as `*.wasm` and check them in to your project's `wit`
34//! directory. The hope is that in the future it will be easier to manage these
35//! files with registry tooling and they won't have to be copied manually.
36//! For reference documentation on the layout of the `wit` directory see
37//! [`wit_parser::Resolve::push_dir`].
38//!
39//! [`bindgen!`]: crate::component::bindgen
40//! [`wit_parser::Resolve::push_dir`]: https://docs.rs/wit-parser/latest/wit_parser/struct.Resolve.html#method.push_dir
41//! [open an issue]: https://github.com/bytecodealliance/wasmtime/issues/new
42
43#![expect(
44    missing_docs,
45    reason = "bindgen-generated types known to not have docs"
46)]
47
48// This "hack" will shadow the `bindgen` macro in general and be inherited to
49// following modules by default. This enables documenting sources as-is while
50// additionally customizing them to working within the wasmtime crate itself by
51// injecting a configuration option to change how the `wasmtime` crate is
52// referenced in the generated output.
53//
54// Note that this has an additional "hack" such that when docs.rs is documenting
55// this crate (or CI) then `include_generated_code_from_file` is unconditionally
56// turned on. This makes `[source]` links on documentation show the actual
57// generated code rather than just the `bindgen!` macro invocation, which can be
58// helpful when exploring code.
59#[cfg(docsrs)]
60macro_rules! bindgen {
61    ({$($t:tt)*}) => (crate::component::bindgen!({
62        $($t)*
63        wasmtime_crate: crate,
64        include_generated_code_from_file: true,
65    }););
66}
67#[cfg(not(docsrs))]
68macro_rules! bindgen {
69    ({$($t:tt)*}) => (crate::component::bindgen!({
70        $($t)*
71        wasmtime_crate: crate,
72    }););
73}
74
75/// A "hello world" style example.
76///
77/// This example loads a component which has access to a single host function.
78/// The exported function is called on an instantiation of the component.
79///
80/// ```rust
81/// use wasmtime::component::*;
82/// use wasmtime::{Engine, Store};
83///
84#[doc = include_str!("./_0_hello_world.rs")]
85///
86/// struct MyState {
87///     name: String,
88/// }
89///
90/// // Imports into the world, like the `name` import for this world, are
91/// // satisfied through traits.
92/// impl HelloWorldImports for MyState {
93///     fn name(&mut self) -> String {
94///         self.name.clone()
95///     }
96/// }
97///
98/// fn main() -> wasmtime::Result<()> {
99/// #   if true { return Ok(()) }
100///     // Compile the `Component` that is being run for the application.
101///     let engine = Engine::default();
102///     let component = Component::from_file(&engine, "./your-component.wasm")?;
103///
104///     // Instantiation of bindings always happens through a `Linker`.
105///     // Configuration of the linker is done through a generated `add_to_linker`
106///     // method on the bindings structure.
107///     //
108///     // Note that the function provided here is a projection from `T` in
109///     // `Store<T>` to `&mut U` where `U` implements the `HelloWorldImports`
110///     // trait. In this case the `T`, `MyState`, is stored directly in the
111///     // structure so no projection is necessary here.
112///     //
113///     // Note that the second type parameter of `add_to_linker` is chosen here
114///     // as the built-in `HasSelf` type in Wasmtime. This effectively says
115///     // that our function isn't actually projecting, it's returning the
116///     // input, so `HasSelf<_>` is a convenience to avoid writing a custom
117///     // `HasData` implementation.
118///     let mut linker = Linker::new(&engine);
119///     HelloWorld::add_to_linker::<_, HasSelf<_>>(&mut linker, |state| state)?;
120///
121///     // As with the core wasm API of Wasmtime instantiation occurs within a
122///     // `Store`. The bindings structure contains an `instantiate` method which
123///     // takes the store, component, and linker. This returns the `bindings`
124///     // structure which is an instance of `HelloWorld` and supports typed access
125///     // to the exports of the component.
126///     let mut store = Store::new(
127///         &engine,
128///         MyState {
129///             name: "me".to_string(),
130///         },
131///     );
132///     let bindings = HelloWorld::instantiate(&mut store, &component, &linker)?;
133///
134///     // Here our `greet` function doesn't take any parameters for the component,
135///     // but in the Wasmtime embedding API the first argument is always a `Store`.
136///     bindings.call_greet(&mut store)?;
137///     Ok(())
138/// }
139/// ```
140pub mod _0_hello_world;
141
142/// An example of generated bindings for top-level imported functions and
143/// interfaces into a world.
144///
145/// The code used to generate this module is:
146///
147/// ```rust
148/// use wasmtime::component::*;
149/// use wasmtime::{Engine, Store};
150///
151#[doc = include_str!("./_1_world_imports.rs")]
152///
153/// struct MyState {
154///     // ...
155/// }
156///
157/// impl my_custom_host::Host for MyState {
158///     fn tick(&mut self) {
159///         todo!()
160///     }
161/// }
162///
163/// impl MyWorldImports for MyState {
164///     fn greet(&mut self) -> String {
165///         todo!()
166///     }
167///
168///     fn log(&mut self, msg: String) {
169///         println!("{msg}");
170///     }
171/// }
172///
173/// fn main() -> wasmtime::Result<()> {
174/// #   if true { return Ok(()) }
175///     let engine = Engine::default();
176///     let component = Component::from_file(&engine, "./your-component.wasm")?;
177///
178///     let mut linker = Linker::new(&engine);
179///     MyWorld::add_to_linker::<_, HasSelf<_>>(&mut linker, |state| state)?;
180///
181///     let mut store = Store::new(
182///         &engine,
183///         MyState { /* ... */ },
184///     );
185///     let bindings = MyWorld::instantiate(&mut store, &component, &linker)?;
186///
187///     // ... NB: this world has no exports just yet so not much can be done
188///     // with `bindings`.
189///
190///     Ok(())
191/// }
192/// ```
193pub mod _1_world_imports;
194
195/// An example of generated bindings for top-level exported functions for a
196/// world.
197///
198/// Some notable generated items here are:
199///
200/// * [`my::project::host::Host`](_2_world_exports::my::project::host::Host) -
201///   the generated trait for the `interface host` import.
202/// * [`exports::demo::Guest`](_2_world_exports::exports::demo::Guest) -
203///   the generated structured used to invoke exports on the returned instance.
204/// * [`HelloWorld`](_2_world_exports::HelloWorld) -
205///   the overall generated structure representing our `world`.
206///
207/// ```rust
208/// use wasmtime::component::*;
209/// use wasmtime::{Engine, Store};
210///
211#[doc = include_str!("./_2_world_exports.rs")]
212///
213/// struct MyState {
214///     // ...
215/// }
216///
217/// # mod rand { pub fn thread_rng() -> G { G } pub struct G; impl G { pub fn r#gen(&self) -> u32 { 0 } } }
218/// // Note that the trait here is per-interface and within a submodule now.
219/// impl my::project::host::Host for MyState {
220///     fn gen_random_integer(&mut self) -> u32 {
221///         rand::thread_rng().r#gen()
222///     }
223///
224///     fn sha256(&mut self, bytes: Vec<u8>) -> String {
225///         // ...
226/// #       panic!()
227///     }
228/// }
229///
230/// fn main() -> wasmtime::Result<()> {
231/// #   if true { return Ok(()) }
232///     let engine = Engine::default();
233///     let component = Component::from_file(&engine, "./your-component.wasm")?;
234///
235///     let mut linker = Linker::new(&engine);
236///     HelloWorld::add_to_linker::<_, HasSelf<_>>(&mut linker, |state| state)?;
237///
238///     let mut store = Store::new(
239///         &engine,
240///         MyState { /* ... */ },
241///     );
242///     let bindings = HelloWorld::instantiate(&mut store, &component, &linker)?;
243///
244///     // Note that the `demo` method returns a `&exports::Demo::Guest`
245///     // through which we can run the methods on that interface.
246///     bindings.demo().call_run(&mut store)?;
247///     Ok(())
248/// }
249/// ```
250pub mod _2_world_exports;
251
252/// Example of generating bindings for imported interfaces in a world.
253///
254/// Notable parts of this example are:
255///
256/// * Imported interfaces use the Rust module system to encapsulate themselves.
257///   The interface imported here is `example:interface-imports/logging` so the
258///   generated trait and types are located in
259///   [`example::interface_imports::logging`][module].
260/// * Types in the `logging` interface are generated in the `logging` module,
261///   for example [`Level`].
262/// * Generated types have implementations of [`ComponentType`], [`Lift`], and
263///   [`Lower`] derived.
264/// * The generated trait that host's must implement is always called [`Host`]
265///   and is located in the generated module.
266///
267/// [module]: _3_interface_imports::example::interface_imports::logging
268/// [`Level`]: _3_interface_imports::example::interface_imports::logging::Level
269/// [`Host`]: _3_interface_imports::example::interface_imports::logging::Host
270/// [`ComponentType`]: crate::component::ComponentType
271/// [`Lift`]: crate::component::Lift
272/// [`Lower`]: crate::component::Lower
273///
274/// ```rust
275/// use wasmtime::component::bindgen;
276/// use example::interface_imports::logging::Level;
277///
278#[doc = include_str!("./_3_interface_imports.rs")]
279///
280/// struct MyState {
281///     // ...
282/// }
283///
284/// impl example::interface_imports::logging::Host for MyState {
285///     fn log(&mut self, level: Level, msg: String) {
286///         // ...
287///     }
288/// }
289/// ```
290pub mod _3_interface_imports;
291
292/// Example of generating bindings for imported resources in a world.
293///
294/// Notable parts of this example are:
295///
296/// * Imported resources from the host are represented as traits, in this case
297///   [`HostLogger`].
298/// * The per-interface [`Host`] trait still exists but has a supertrait of
299///   [`HostLogger`].
300/// * Resources are represented as [`Resource<T>`] and it's recommended to
301///   specify a `with` key to indicate what host type you'd like to use for
302///   each resource.
303/// * A [`ResourceTable`] can be used to manage resources when working with
304///   guests.
305///
306/// [`Host`]: _4_imported_resources::example::imported_resources::logging::Host
307/// [`HostLogger`]: _4_imported_resources::example::imported_resources::logging::HostLogger
308/// [`Resource<T>`]: crate::component::Resource
309/// [`ResourceTable`]: crate::component::ResourceTable
310///
311/// ```rust
312/// use wasmtime::Result;
313/// use wasmtime::component::{bindgen, ResourceTable, Resource};
314/// use example::imported_resources::logging::{Level, Host, HostLogger};
315///
316#[doc = include_str!("./_4_imported_resources.rs")]
317///
318/// #[derive(Default)]
319/// struct MyState {
320///     // Manages the mapping of `MyLogger` structures to `Resource<MyLogger>`.
321///     table: ResourceTable,
322/// }
323///
324/// // There are no free-functions on `interface logging`, so this is an empty
325/// // impl.
326/// impl Host for MyState {}
327///
328/// // This separate `HostLogger` trait serves to act as a namespace for just
329/// // the `logger`-related resource methods.
330/// impl HostLogger for MyState {
331///     // A `constructor` in WIT maps to a `new` function in Rust.
332///     fn new(&mut self, max_level: Level) -> Result<Resource<MyLogger>> {
333///         let id = self.table.push(MyLogger { max_level })?;
334///         Ok(id)
335///     }
336///
337///     fn get_max_level(&mut self, logger: Resource<MyLogger>) -> Result<Level> {
338///         debug_assert!(!logger.owned());
339///         let logger = self.table.get(&logger)?;
340///         Ok(logger.max_level)
341///     }
342///
343///     fn set_max_level(&mut self, logger: Resource<MyLogger>, level: Level) -> Result<()> {
344///         debug_assert!(!logger.owned());
345///         let logger = self.table.get_mut(&logger)?;
346///         logger.max_level = level;
347///         Ok(())
348///     }
349///
350///     fn log(&mut self, logger: Resource<MyLogger>, level: Level, msg: String) -> Result<()> {
351///         debug_assert!(!logger.owned());
352///         let logger = self.table.get_mut(&logger)?;
353///         if (level as u32) <= (logger.max_level as u32) {
354///             println!("{msg}");
355///         }
356///         Ok(())
357///     }
358///
359///     fn drop(&mut self, logger: Resource<MyLogger>) -> Result<()> {
360///         debug_assert!(logger.owned());
361///         let _logger: MyLogger = self.table.delete(logger)?;
362///         // ... custom destruction logic here if necessary, otherwise
363///         // a `Drop for MyLogger` would also work.
364///         Ok(())
365///     }
366/// }
367///
368/// # fn main() {}
369/// ```
370pub mod _4_imported_resources;
371
372/// Example of all kinds of structures of exports from a world.
373///
374/// * Top-level functions in a `world` are exported directly on the generated
375///   structure such as [`call_run`].
376/// * All other exports are otherwise scoped with generated traits/types
377///   in a top level [`exports`] module.
378/// * Exported named interfaces are located at the root of the [`exports`]
379///   module, such as [`exports::environment`].
380/// * Interfaces are all bound with a structure called `Guest` which has typed
381///   functions for each export that can be called. For example
382///   [`exports::environment::Guest`][guest1] and
383///   [`exports::example::world_exports::units::Guest`][guest2].
384/// * Interfaces exported by their id are modeled with multiple namespacing
385///   modules, such as [`exports::example::world_exports::units`][units].
386///
387/// [`call_run`]: _5_all_world_export_kinds::WithExports::call_run
388/// [`exports`]: _5_all_world_export_kinds::exports
389/// [`exports::environment`]: _5_all_world_export_kinds::exports::environment
390/// [guest1]: _5_all_world_export_kinds::exports::environment::Guest
391/// [guest2]: _5_all_world_export_kinds::exports::example::world_exports::units::Guest
392/// [units]: _5_all_world_export_kinds::exports::example::world_exports::units
393///
394/// ```rust
395/// use wasmtime::{Result, Engine, Store};
396/// use wasmtime::component::{bindgen, Component, Linker, HasSelf};
397///
398#[doc = include_str!("./_5_all_world_export_kinds.rs")]
399///
400/// struct MyState;
401///
402/// impl WithExportsImports for MyState {
403///     fn log(&mut self, msg: String) {
404///         println!("{msg}");
405///     }
406/// }
407///
408/// fn main() -> Result<()> {
409/// #   if true { return Ok(()) }
410///     let engine = Engine::default();
411///     let component = Component::from_file(&engine, "./your-component.wasm")?;
412///
413///     let mut linker = Linker::new(&engine);
414///     WithExports::add_to_linker::<_, HasSelf<_>>(&mut linker, |state| state)?;
415///
416///     let mut store = Store::new(&engine, MyState);
417///     let bindings = WithExports::instantiate(&mut store, &component, &linker)?;
418///
419///     // top-level functions are exported directly on `WithExports` and are
420///     // all prefixed with `call_*`.
421///     bindings.call_run(&mut store)?;
422///
423///     // exported named interfaces are named directly after their export name
424///     // and the `&Guest` return value has `call_*` functions on it.
425///     bindings.environment().call_set(&mut store, "key", "value")?;
426///     let value = bindings.environment().call_get(&mut store, "key")?;
427///     assert_eq!(value, "value");
428///
429///     // exported interfaces by id are similar to export-by-name except that
430///     // the exported name is modeled after the full id, not just the name.
431///     let units = bindings.example_world_exports_units();
432///     let bytes = 1 << 30 + 1 << 20;
433///     let s = units.call_bytes_to_string(&mut store, bytes)?;
434///     println!("{bytes} = {s}");
435///
436///     let (seconds, ns) = (1 << 20, 12345);
437///     let s = units.call_duration_to_string(&mut store, seconds, ns)?;
438///     println!("{seconds}s + {ns}ns = {s}");
439///     Ok(())
440/// }
441/// ```
442pub mod _5_all_world_export_kinds;
443
444/// Example of a world which exports a resource.
445///
446/// * Guest resources are modeled as [`ResourceAny`]. Note that this type is not
447///   specialized per-resource at this time so care must be taken to not mix
448///   them up.
449/// * Resource-related methods are a projection from a [`Guest`] structure, for
450///   example to [`GuestLogger`] here.
451/// * Resource-related methods all take a [`ResourceAny`] as an argument or
452///   a return value.
453/// * The [`ResourceAny`] must be explicitly dropped.
454///
455/// [`ResourceAny`]: crate::component::ResourceAny
456/// [`Guest`]: _6_exported_resources::exports::example::exported_resources::logging::Guest
457/// [`GuestLogger`]: _6_exported_resources::exports::example::exported_resources::logging::GuestLogger
458///
459/// ```rust
460/// use wasmtime::{Result, Engine, Store};
461/// use wasmtime::component::{bindgen, Component, Linker};
462/// use self::exports::example::exported_resources::logging::Level;
463///
464#[doc = include_str!("./_6_exported_resources.rs")]
465///
466/// struct MyState;
467///
468/// fn main() -> Result<()> {
469/// #   if true { return Ok(()) }
470///     let engine = Engine::default();
471///     let component = Component::from_file(&engine, "./your-component.wasm")?;
472///
473///     let linker = Linker::new(&engine);
474///     // ... this small example has no imports so nothing is added here, but
475///     // if you had imports this is where they'd go.
476///
477///     let mut store = Store::new(&engine, MyState);
478///     let bindings = ExportSomeResources::instantiate(&mut store, &component, &linker)?;
479///     let guest = bindings.example_exported_resources_logging();
480///     let logger = guest.logger();
481///
482///     // Resource methods are all attached to `logger` and take the
483///     // `ResourceAny` parameter explicitly.
484///     let my_logger = logger.call_constructor(&mut store, Level::Warn)?;
485///     assert_eq!(logger.call_get_max_level(&mut store, my_logger)?, Level::Warn);
486///     logger.call_set_max_level(&mut store, my_logger, Level::Info)?;
487///
488///     logger.call_log(&mut store, my_logger, Level::Debug, "hello!")?;
489///
490///     // The `ResourceAny` type has no destructor but when the host is done
491///     // with it it needs to invoke the guest-level destructor.
492///     my_logger.resource_drop(&mut store)?;
493///
494///     Ok(())
495/// }
496/// ```
497pub mod _6_exported_resources;
498
499/// Example of generating **async** bindings for imported resources in a world.
500///
501/// Notable differences from [`_4_imported_resources`] are:
502/// * async functions are used
503/// * enabled async in bindgen! macro
504///
505/// See [wasi_async_example](https://github.com/bytecodealliance/wasmtime/blob/main/examples/wasip1-async/main.rs) for async function calls on a host.
506///
507/// ```rust
508/// use wasmtime::Result;
509/// use wasmtime::component::{bindgen, ResourceTable, Resource};
510/// use example::imported_resources::logging::{Level, Host, HostLogger};
511///
512#[doc = include_str!("./_7_async.rs")]
513///
514/// #[derive(Default)]
515/// struct MyState {
516///     // Manages the mapping of `MyLogger` structures to `Resource<MyLogger>`.
517///     table: ResourceTable,
518/// }
519///
520/// // There are no free-functions on `interface logging`, so this is an empty
521/// // impl.
522/// impl Host for MyState {}
523///
524/// // This separate `HostLogger` trait serves to act as a namespace for just
525/// // the `logger`-related resource methods.
526/// impl HostLogger for MyState {
527///     // A `constructor` in WIT maps to a `new` function in Rust.
528///     async fn new(&mut self, max_level: Level) -> Result<Resource<MyLogger>> {
529///         let id = self.table.push(MyLogger { max_level })?;
530///         Ok(id)
531///     }
532///
533///     async fn get_max_level(&mut self, logger: Resource<MyLogger>) -> Result<Level> {
534///         debug_assert!(!logger.owned());
535///         let logger = self.table.get(&logger)?;
536///         Ok(logger.max_level)
537///     }
538///
539///     async fn set_max_level(&mut self, logger: Resource<MyLogger>, level: Level) -> Result<()> {
540///         debug_assert!(!logger.owned());
541///         let logger = self.table.get_mut(&logger)?;
542///         logger.max_level = level;
543///         Ok(())
544///     }
545///
546///     async fn log(&mut self, logger: Resource<MyLogger>, level: Level, msg: String) -> Result<()> {
547///         debug_assert!(!logger.owned());
548///         let logger = self.table.get_mut(&logger)?;
549///         if (level as u32) <= (logger.max_level as u32) {
550///             println!("{msg}");
551///         }
552///         Ok(())
553///     }
554///
555///     async fn drop(&mut self, logger: Resource<MyLogger>) -> Result<()> {
556///         debug_assert!(logger.owned());
557///         let _logger: MyLogger = self.table.delete(logger)?;
558///         // ... custom destruction logic here if necessary, otherwise
559///         // a `Drop for MyLogger` would also work.
560///         Ok(())
561///     }
562/// }
563///
564/// # fn main() {}
565/// ```
566pub mod _7_async;