static_config/
lib.rs

1use anyhow::{Context, Result};
2use config::{create_config, Config};
3use std::collections::HashMap;
4use wasm_metadata::Producers;
5use wit_component::{metadata, ComponentEncoder, DecodedWasm, StringEncoding};
6
7pub mod config;
8mod walrus_ops;
9
10const ADAPTER: &[u8] = include_bytes!("../lib/adapter.wasm");
11const WIT_METADATA: &[u8] = include_bytes!("../lib/package.wasm");
12
13pub fn create_component(values: Vec<(String, String)>) -> Result<Vec<u8>> {
14    let mut config = walrus::ModuleConfig::new();
15    // TODO reconsider?
16    config.generate_name_section(false);
17    let mut module = config.parse(ADAPTER)?;
18    module.name = Some("static-config".into());
19
20    let mut properties = HashMap::new();
21    for (key, value) in values {
22        properties.insert(key, value);
23    }
24
25    let config = &Config {
26        overrides: properties.into_iter().collect(),
27    };
28    create_config(&mut module, config)?;
29
30    let component_type_section_id = module
31        .customs
32        .iter()
33        .find_map(|(id, section)| {
34            let name = section.name();
35            if name.starts_with("component-type:")
36                && section.as_any().is::<walrus::RawCustomSection>()
37            {
38                Some(id)
39            } else {
40                None
41            }
42        })
43        .context("Unable to find component type section")?;
44
45    // decode the component custom section to strip out the unused world exports
46    // before reencoding.
47    let mut component_section = *module
48        .customs
49        .delete(component_type_section_id)
50        .context("Unable to find component section")?
51        .into_any()
52        .downcast::<walrus::RawCustomSection>()
53        .unwrap();
54
55    let (resolve, pkg_id) = match wit_component::decode(WIT_METADATA)? {
56        DecodedWasm::WitPackage(resolve, pkg_id) => (resolve, pkg_id),
57        DecodedWasm::Component(..) => {
58            anyhow::bail!("expected a WIT package, found a component")
59        }
60    };
61
62    let world = resolve.select_world(&[pkg_id], Some("adapter"))?;
63
64    let mut producers = Producers::default();
65    producers.add("processed-by", "static-config", env!("CARGO_PKG_VERSION"));
66
67    component_section.data =
68        metadata::encode(&resolve, world, StringEncoding::UTF8, Some(&producers))?;
69
70    module.customs.add(component_section);
71
72    let bytes = module.emit_wasm();
73
74    // now adapt the virtualized component
75    let mut encoder = ComponentEncoder::default().validate(true).module(&bytes)?;
76    let encoded = encoder.encode()?;
77
78    Ok(encoded)
79}