xref: /wasmtime-44.0.1/examples/wasip2/main.rs (revision bda02c19)
1 //! Example of instantiating a wasm module which uses WASI imports.
2 
3 /*
4 You can execute this example with:
5     cmake examples/
6     cargo run --example wasip2
7 */
8 
9 use wasmtime::component::{Component, Linker, ResourceTable};
10 use wasmtime::*;
11 use wasmtime_wasi::p2::bindings::sync::Command;
12 use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
13 
14 pub struct ComponentRunStates {
15     // These two are required basically as a standard way to enable the impl of IoView and
16     // WasiView.
17     // impl of WasiView is required by [`wasmtime_wasi::p2::add_to_linker_sync`]
18     pub wasi_ctx: WasiCtx,
19     pub resource_table: ResourceTable,
20     // You can add other custom host states if needed
21 }
22 
23 impl WasiView for ComponentRunStates {
24     fn ctx(&mut self) -> WasiCtxView<'_> {
25         WasiCtxView {
26             ctx: &mut self.wasi_ctx,
27             table: &mut self.resource_table,
28         }
29     }
30 }
31 
32 fn main() -> Result<()> {
33     // Define the WASI functions globally on the `Config`.
34     let engine = Engine::default();
35     let mut linker = Linker::new(&engine);
36     wasmtime_wasi::p2::add_to_linker_sync(&mut linker)?;
37 
38     // Create a WASI context and put it in a Store; all instances in the store
39     // share this context. `WasiCtx` provides a number of ways to
40     // configure what the target program will have access to.
41     let wasi = WasiCtx::builder().inherit_stdio().inherit_args().build();
42     let state = ComponentRunStates {
43         wasi_ctx: wasi,
44         resource_table: ResourceTable::new(),
45     };
46     let mut store = Store::new(&engine, state);
47 
48     // Instantiate our component with the imports we've created, and run it.
49     let component = Component::from_file(&engine, "target/wasm32-wasip2/debug/wasi.wasm")?;
50     let command = Command::instantiate(&mut store, &component, &linker)?;
51     let program_result = command.wasi_cli_run().call_run(&mut store)?;
52     if program_result.is_err() {
53         std::process::exit(1)
54     }
55 
56     // Alternatively, instead of using `Command`, just instantiate it as a normal component
57     // New states
58     let wasi = WasiCtx::builder().inherit_stdio().inherit_args().build();
59     let state = ComponentRunStates {
60         wasi_ctx: wasi,
61         resource_table: ResourceTable::new(),
62     };
63     let mut store = Store::new(&engine, state);
64     // Instantiate it as a normal component
65     let instance = linker.instantiate(&mut store, &component)?;
66     // Get the index for the exported interface
67     let interface_idx = instance
68         .get_export_index(&mut store, None, "wasi:cli/run@0.2.0")
69         .expect("Cannot get `wasi:cli/run@0.2.0` interface");
70     // Get the index for the exported function in the exported interface
71     let parent_export_idx = Some(&interface_idx);
72     let func_idx = instance
73         .get_export_index(&mut store, parent_export_idx, "run")
74         .expect("Cannot get `run` function in `wasi:cli/run@0.2.0` interface");
75     let func = instance
76         .get_func(&mut store, func_idx)
77         .expect("Unreachable since we've got func_idx");
78     // As the `run` function in `wasi:cli/run@0.2.0` takes no argument and return a WASI result that correspond to a `Result<(), ()>`
79     // Reference:
80     // * https://github.com/WebAssembly/wasi-cli/blob/main/wit/run.wit
81     // * Documentation for [Func::typed](https://docs.rs/wasmtime/latest/wasmtime/component/struct.Func.html#method.typed) and [ComponentNamedList](https://docs.rs/wasmtime/latest/wasmtime/component/trait.ComponentNamedList.html)
82     let typed = func.typed::<(), (Result<(), ()>,)>(&store)?;
83     let (result,) = typed.call(&mut store, ())?;
84     result.map_err(|_| wasmtime::format_err!("error"))
85 }
86