wasmtime_wasi_config/lib.rs
1//! # Wasmtime's [wasi-config] Implementation
2//!
3//! This crate provides a Wasmtime host implementation of the [wasi-config]
4//! API. With this crate, the runtime can run components that call APIs in
5//! [wasi-config] and provide configuration variables for the component.
6//!
7//! # Examples
8//!
9//! The usage of this crate is very similar to other WASI API implementations
10//! such as [wasi:cli] and [wasi:http].
11//!
12//! A common scenario is getting runtime-passed configurations in a [wasi:cli]
13//! component. A standalone example of doing all this looks like:
14//!
15//! ```
16//! use wasmtime::{
17//! component::{Linker, ResourceTable},
18//! Engine, Result, Store,
19//! };
20//! use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
21//! use wasmtime_wasi_config::{WasiConfig, WasiConfigVariables};
22//!
23//! #[tokio::main]
24//! async fn main() -> Result<()> {
25//! let engine = Engine::default();
26//!
27//! let mut store = Store::new(&engine, Ctx {
28//! table: ResourceTable::new(),
29//! wasi_ctx: WasiCtx::builder().build(),
30//! wasi_config_vars: WasiConfigVariables::from_iter(vec![
31//! ("config_key1", "value1"),
32//! ("config_key2", "value2"),
33//! ]),
34//! });
35//!
36//! let mut linker = Linker::<Ctx>::new(&engine);
37//! wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
38//! // add `wasi-config` world's interfaces to the linker
39//! wasmtime_wasi_config::add_to_linker(&mut linker, |h: &mut Ctx| {
40//! WasiConfig::from(&h.wasi_config_vars)
41//! })?;
42//!
43//! // ... use `linker` to instantiate within `store` ...
44//!
45//! Ok(())
46//! }
47//!
48//! struct Ctx {
49//! table: ResourceTable,
50//! wasi_ctx: WasiCtx,
51//! wasi_config_vars: WasiConfigVariables,
52//! }
53//!
54//! impl WasiView for Ctx {
55//! fn ctx(&mut self) -> WasiCtxView<'_> {
56//! WasiCtxView { ctx: &mut self.wasi_ctx, table: &mut self.table }
57//! }
58//! }
59//! ```
60//!
61//! [wasi-config]: https://github.com/WebAssembly/wasi-config
62//! [wasi:cli]: https://docs.rs/wasmtime-wasi/latest
63//! [wasi:http]: https://docs.rs/wasmtime-wasi-http/latest
64
65#![deny(missing_docs)]
66
67use std::collections::HashMap;
68use wasmtime::Result;
69use wasmtime::component::HasData;
70
71mod gen_ {
72 wasmtime::component::bindgen!({
73 path: "wit",
74 world: "wasi:config/imports",
75 imports: { default: trappable },
76 });
77}
78use self::gen_::wasi::config::store as generated;
79
80/// Capture the state necessary for use in the `wasi-config` API implementation.
81#[derive(Default)]
82pub struct WasiConfigVariables(HashMap<String, String>);
83
84impl<S: Into<String>> FromIterator<(S, S)> for WasiConfigVariables {
85 fn from_iter<I: IntoIterator<Item = (S, S)>>(iter: I) -> Self {
86 Self(
87 iter.into_iter()
88 .map(|(k, v)| (k.into(), v.into()))
89 .collect(),
90 )
91 }
92}
93
94impl WasiConfigVariables {
95 /// Create a new runtime configuration.
96 pub fn new() -> Self {
97 Default::default()
98 }
99
100 /// Insert a key-value pair into the configuration map.
101 pub fn insert(&mut self, key: impl Into<String>, value: impl Into<String>) -> &mut Self {
102 self.0.insert(key.into(), value.into());
103 self
104 }
105}
106
107/// A wrapper capturing the needed internal `wasi-config` state.
108pub struct WasiConfig<'a> {
109 vars: &'a WasiConfigVariables,
110}
111
112impl<'a> From<&'a WasiConfigVariables> for WasiConfig<'a> {
113 fn from(vars: &'a WasiConfigVariables) -> Self {
114 Self { vars }
115 }
116}
117
118impl<'a> WasiConfig<'a> {
119 /// Create a new view into the `wasi-config` state.
120 pub fn new(vars: &'a WasiConfigVariables) -> Self {
121 Self { vars }
122 }
123}
124
125impl generated::Host for WasiConfig<'_> {
126 fn get(&mut self, key: String) -> Result<Result<Option<String>, generated::Error>> {
127 Ok(Ok(self.vars.0.get(&key).map(|s| s.to_owned())))
128 }
129
130 fn get_all(&mut self) -> Result<Result<Vec<(String, String)>, generated::Error>> {
131 Ok(Ok(self
132 .vars
133 .0
134 .iter()
135 .map(|(k, v)| (k.to_string(), v.to_string()))
136 .collect()))
137 }
138}
139
140/// Add all the `wasi-config` world's interfaces to a [`wasmtime::component::Linker`].
141pub fn add_to_linker<T: 'static>(
142 l: &mut wasmtime::component::Linker<T>,
143 f: fn(&mut T) -> WasiConfig<'_>,
144) -> Result<()> {
145 generated::add_to_linker::<T, HasWasiConfig>(l, f)?;
146 Ok(())
147}
148
149struct HasWasiConfig;
150
151impl HasData for HasWasiConfig {
152 type Data<'a> = WasiConfig<'a>;
153}