use wasmtime::component::{HasData, ResourceTable};
use wasmtime_wasi::cli::{WasiCli, WasiCliView};
use wasmtime_wasi::clocks::{WasiClocks, WasiClocksView as _};
use wasmtime_wasi::p2::bindings::{cli, clocks, io, random};
use wasmtime_wasi::random::{WasiRandom, WasiRandomView as _};
pub(crate) fn register_minimal_wasi<T: wasmtime_wasi::WasiView>(
linker: &mut wasmtime::component::Linker<T>,
) -> Result<(), wasmtime::Error> {
clocks::wall_clock::add_to_linker::<T, WasiClocks>(linker, T::clocks)?;
clocks::monotonic_clock::add_to_linker::<T, WasiClocks>(linker, T::clocks)?;
random::random::add_to_linker::<T, WasiRandom>(linker, T::random)?;
random::insecure::add_to_linker::<T, WasiRandom>(linker, T::random)?;
random::insecure_seed::add_to_linker::<T, WasiRandom>(linker, T::random)?;
Ok(())
}
struct HasIo;
impl HasData for HasIo {
type Data<'a> = &'a mut ResourceTable;
}
pub(crate) fn register_command_adapter_wasi<T: wasmtime_wasi::WasiView>(
linker: &mut wasmtime::component::Linker<T>,
) -> Result<(), wasmtime::Error> {
register_minimal_wasi(linker)?;
io::error::add_to_linker::<T, HasIo>(linker, |t| t.ctx().table)?;
io::poll::add_to_linker::<T, HasIo>(linker, |t| t.ctx().table)?;
io::streams::add_to_linker::<T, HasIo>(linker, |t| t.ctx().table)?;
cli::environment::add_to_linker::<T, WasiCli>(linker, T::cli)?;
cli::exit::add_to_linker::<T, WasiCli>(linker, T::cli)?;
cli::stdin::add_to_linker::<T, WasiCli>(linker, T::cli)?;
cli::stdout::add_to_linker::<T, WasiCli>(linker, T::cli)?;
cli::stderr::add_to_linker::<T, WasiCli>(linker, T::cli)?;
cli::terminal_input::add_to_linker::<T, WasiCli>(linker, T::cli)?;
cli::terminal_output::add_to_linker::<T, WasiCli>(linker, T::cli)?;
cli::terminal_stdin::add_to_linker::<T, WasiCli>(linker, T::cli)?;
cli::terminal_stdout::add_to_linker::<T, WasiCli>(linker, T::cli)?;
cli::terminal_stderr::add_to_linker::<T, WasiCli>(linker, T::cli)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_no_full_wasi_registration_in_crate() {
let src = include_str!("runtime.rs");
assert!(
!src.contains("add_to_linker_async"),
"runtime.rs must not use add_to_linker_async"
);
let src = include_str!("wasm_plugin_context.rs");
assert!(
!src.contains("add_to_linker_async"),
"wasm_plugin_context.rs must not use add_to_linker_async"
);
let src = include_str!("source_host.rs");
assert!(
!src.contains("add_to_linker_async"),
"source_host.rs must not use add_to_linker_async"
);
}
#[test]
fn test_no_inherit_stderr_in_crate() {
let src = include_str!("runtime.rs");
assert!(
!src.contains("inherit_stderr"),
"runtime.rs must not call inherit_stderr"
);
let src = include_str!("host_functions.rs");
assert!(
!src.contains("inherit_stderr"),
"host_functions.rs must not call inherit_stderr"
);
let src = include_str!("stream_bridge.rs");
assert!(
!src.contains("inherit_stderr"),
"stream_bridge.rs must not call inherit_stderr"
);
}
#[test]
fn test_register_minimal_wasi_succeeds() {
let engine = wasmtime::Engine::new(&wasmtime::Config::new()).expect("engine");
let mut linker: wasmtime::component::Linker<crate::runtime::WasmHostState> =
wasmtime::component::Linker::new(&engine);
register_minimal_wasi(&mut linker).expect("clocks+random register");
}
#[test]
fn test_register_command_adapter_wasi_succeeds() {
let engine = wasmtime::Engine::new(&wasmtime::Config::new()).expect("engine");
let mut linker: wasmtime::component::Linker<crate::runtime::WasmHostState> =
wasmtime::component::Linker::new(&engine);
register_command_adapter_wasi(&mut linker).expect("command-adapter surface registers");
}
#[test]
fn test_no_filesystem_or_sockets_registration() {
let src = include_str!("wasi_surface.rs");
let fs: String = ["filesystem", "::"].concat();
let sock: String = ["sockets", "::"].concat();
assert!(
!src.contains(&fs) && !src.contains(&sock),
"wasi_surface.rs must not register wasi:filesystem or wasi:sockets"
);
}
}