uni_plugin_wasm/host_state.rs
1//! Per-`Store` host state.
2//!
3//! Every wasmtime `Store<T>` carries a `T` that the host's `Linker`
4//! references when wiring up imports. Our `T` is `HostState` — it
5//! holds:
6//!
7//! - **WASI context** — most Rust→wasm32-wasip2 plugins import
8//! `wasi:cli`, `wasi:io`, `wasi:clocks`, etc., even when their
9//! user-facing logic doesn't need filesystem / network access
10//! (the standard library pulls these in transitively). Without
11//! `wasmtime-wasi` linked, instantiation fails with
12//! `component imports instance "wasi:io/poll@0.2.6", but a
13//! matching implementation was not found in the linker`.
14//! - **Effective capability set** — so capability-gated host fns
15//! can dispatch on the granted set.
16
17use std::sync::Arc;
18
19use uni_plugin::{CapabilitySet, HttpEgress};
20use wasmtime_wasi::{ResourceTable, WasiCtx, WasiCtxBuilder, WasiCtxView, WasiView};
21
22/// State threaded through every wasmtime `Store<HostState>`.
23pub struct HostState {
24 /// Effective capability set (rich, with attenuation patterns) granted to
25 /// the plugin instance — capability-gated host fns dispatch + enforce
26 /// call-time attenuation against it.
27 pub effective: CapabilitySet,
28 /// HTTP egress backing the `host-net` interface, when granted + configured.
29 pub http: Option<Arc<dyn HttpEgress>>,
30 /// WASI context — minimal, no preopens, no inherited stdio.
31 /// Plugins requesting filesystem / network access go through
32 /// capability-gated host fns, not raw WASI preopens.
33 pub wasi: WasiCtx,
34 /// WASI resource table.
35 pub table: ResourceTable,
36}
37
38impl HostState {
39 /// Construct a fresh `HostState` with the given effective caps + egress.
40 ///
41 /// The WASI context starts minimal — no preopens, no inherited
42 /// stdio, no environment.
43 #[must_use]
44 pub fn new(effective: CapabilitySet, http: Option<Arc<dyn HttpEgress>>) -> Self {
45 let wasi = WasiCtxBuilder::new().build();
46 Self {
47 effective,
48 http,
49 wasi,
50 table: ResourceTable::new(),
51 }
52 }
53}
54
55impl std::fmt::Debug for HostState {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 f.debug_struct("HostState")
58 .field("effective", &self.effective)
59 .field("http", &self.http.is_some())
60 .finish_non_exhaustive()
61 }
62}
63
64impl WasiView for HostState {
65 fn ctx(&mut self) -> WasiCtxView<'_> {
66 WasiCtxView {
67 ctx: &mut self.wasi,
68 table: &mut self.table,
69 }
70 }
71}