polymorph_webcrypto_wasmtime/standalone.rs
1//! Ready-made embedding for hosts whose component imports only
2//! `polymorph:webcrypto`: the canonical store state and the engine/linker/store
3//! setup this repository's drivers share (the demo host and the
4//! conformance adapter), so the engine configuration the async imports
5//! require has one definition.
6//!
7//! Hosts with store state of their own implement [`WasiWebcryptoView`] on
8//! their own type and call [`add_to_linker`](crate::add_to_linker)
9//! directly instead.
10
11use std::path::Path;
12
13use wasmtime::component::{Component, HasData, Linker, ResourceTable};
14use wasmtime::error::Context as _;
15use wasmtime::{Config, Engine, Store};
16
17use crate::{WasiWebcryptoCtx, WasiWebcryptoCtxView, WasiWebcryptoView};
18
19/// The store state: the WebCrypto host context plus the resource table its
20/// keys and computations live in.
21pub struct Ctx {
22 /// The WebCrypto host context.
23 pub webcrypto: WasiWebcryptoCtx,
24 /// The table the host's resources live in.
25 pub table: ResourceTable,
26}
27
28impl HasData for Ctx {
29 type Data<'a> = &'a mut Self;
30}
31
32impl WasiWebcryptoView for Ctx {
33 fn webcrypto(&mut self) -> WasiWebcryptoCtxView<'_> {
34 WasiWebcryptoCtxView {
35 ctx: &mut self.webcrypto,
36 table: &mut self.table,
37 }
38 }
39}
40
41/// An engine configured for the component-model async ABI the
42/// `polymorph:webcrypto` imports use.
43pub fn engine() -> wasmtime::Result<Engine> {
44 let mut config = Config::new();
45 config.wasm_component_model(true);
46 config.wasm_component_model_async(true);
47 Engine::new(&config)
48}
49
50/// Load the component at `path` and prepare everything an instantiation
51/// needs: a linker with the `polymorph:webcrypto` imports added, and a store
52/// whose state carries `webcrypto`.
53pub fn load(
54 path: &Path,
55 webcrypto: WasiWebcryptoCtx,
56) -> wasmtime::Result<(Component, Linker<Ctx>, Store<Ctx>)> {
57 let engine = engine()?;
58 let component = Component::from_file(&engine, path)
59 .with_context(|| format!("loading component {}", path.display()))?;
60 let mut linker: Linker<Ctx> = Linker::new(&engine);
61 // The canned embedding is the demo and conformance-driver path, and
62 // the conformance manifest declares the wasmtime target missing no
63 // features — so the `@unstable`-gated interfaces are all served here,
64 // unlike `add_to_linker`'s default.
65 crate::add_to_linker_with_options(
66 &mut linker,
67 crate::LinkOptions::default()
68 .sha1_checked(true)
69 .rsa_sign(true)
70 .rsa_oaep_decrypt(true),
71 )?;
72 let store = Store::new(
73 &engine,
74 Ctx {
75 webcrypto,
76 table: ResourceTable::new(),
77 },
78 );
79 Ok((component, linker, store))
80}