1 use anyhow::Context;
2 use std::{fs, path::Path};
3 
4 use wasmtime::{
5     component::{bindgen, Component, Linker},
6     Config, Engine, Result, Store,
7 };
8 
9 // Generate bindings of the guest and host components.
10 bindgen!("convert" in "./examples/component/convert.wit");
11 
12 struct HostComponent;
13 
14 // Implementation of the host interface defined in the wit file.
15 impl host::Host for HostComponent {
16     fn multiply(&mut self, a: f32, b: f32) -> f32 {
17         a * b
18     }
19 }
20 
21 struct MyState {
22     host: HostComponent,
23 }
24 
25 /// This function is only needed until rust can natively output a component.
26 ///
27 /// Generally embeddings should not be expected to do this programmatically, but instead
28 /// language specific tooling should be used, for example in Rust `cargo component`
29 /// is a good way of doing that: https://github.com/bytecodealliance/cargo-component
30 ///
31 /// In this example we convert the code here to simplify the testing process and build system.
32 fn convert_to_component(path: impl AsRef<Path>) -> Result<Vec<u8>> {
33     let bytes = &fs::read(&path).context("failed to read input file")?;
34     wit_component::ComponentEncoder::default()
35         .module(&bytes)?
36         .encode()
37 }
38 
39 fn main() -> Result<()> {
40     // Create an engine with the component model enabled (disabled by default).
41     let engine = Engine::new(Config::new().wasm_component_model(true))?;
42 
43     // NOTE: The wasm32-unknown-unknown target is used here for simplicity, real world use cases
44     // should probably use the wasm32-wasip1 target, and enable wasi preview2 within the component
45     // model.
46     let component = convert_to_component("target/wasm32-unknown-unknown/debug/guest.wasm")?;
47 
48     // Create our component and call our generated host function.
49     let component = Component::from_binary(&engine, &component)?;
50     let mut store = Store::new(
51         &engine,
52         MyState {
53             host: HostComponent {},
54         },
55     );
56     let mut linker = Linker::new(&engine);
57     host::add_to_linker(&mut linker, |state: &mut MyState| &mut state.host)?;
58     let convert = Convert::instantiate(&mut store, &component, &linker)?;
59     let result = convert.call_convert_celsius_to_fahrenheit(&mut store, 23.4)?;
60     println!("Converted to: {result:?}");
61     Ok(())
62 }
63