Skip to main content

perry_wit/component/
mod.rs

1//! In-process WIT embedding and WebAssembly component encoding.
2
3pub(crate) mod reactions;
4pub mod wit;
5
6use std::{borrow::Cow, path::Path};
7
8use anyhow::{Context, Result};
9use wit_component::{ComponentEncoder, StringEncoding, embed_component_metadata};
10
11/// Embeds WIT contract metadata into a core WebAssembly module and encodes it into a component.
12pub fn embed_and_encode(
13    core_wasm: &[u8],
14    wit_dir: &Path,
15    world_name: Option<&str>,
16) -> Result<Vec<u8>> {
17    let (resolve, pkg_id) = wit::resolve_wit(wit_dir)?;
18    let world_id = resolve
19        .select_world(&[pkg_id], world_name)
20        .with_context(|| format!("selecting world {:?}", world_name))?;
21
22    encode_resolved(core_wasm, &resolve, world_id)
23}
24
25/// Encode the resolved world directly. Modules using promise signals carry the
26/// private [reactions::ANCHOR] export only during component encoding.
27pub(crate) fn encode_resolved(
28    core_wasm: &[u8],
29    resolve: &wit_parser::Resolve,
30    world: wit_parser::WorldId,
31) -> Result<Vec<u8>> {
32    let signals = reactions::uses_signals(core_wasm)?;
33    let (mut core, resolve) = if signals {
34        let (core, resolve) = reactions::prepare(core_wasm, resolve, world)?;
35        (core, Cow::Owned(resolve))
36    } else {
37        (core_wasm.to_vec(), Cow::Borrowed(resolve))
38    };
39    embed_component_metadata(&mut core, &resolve, world, StringEncoding::UTF8, false)
40        .context("embedding component metadata")?;
41    let component = ComponentEncoder::default()
42        .module(&core)
43        .context("configuring component encoder")?
44        .validate(true)
45        .encode()
46        .context("encoding component")?;
47    let component = if signals {
48        reactions::hide(&component)?
49    } else {
50        component
51    };
52    crate::audit::validate_guest(&component).context("validating stackless component")?;
53    Ok(component)
54}