use thiserror::Error;
use wit_component::{ComponentEncoder, StringEncoding, embed_component_metadata};
use wit_parser::Resolve;
use crate::wit::WORLD_NAME;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum ComponentWrapError {
#[error("WIT failed to parse: {reason}")]
WitParse {
reason: String,
},
#[error("WIT does not declare a world named '{WORLD_NAME}': {reason}")]
WorldMissing {
reason: String,
},
#[error("failed to embed component-type metadata into core module: {reason}")]
EmbedFailed {
reason: String,
},
#[error("ComponentEncoder rejected the core module: {reason}")]
EncoderRejected {
reason: String,
},
#[error("ComponentEncoder failed to encode the component: {reason}")]
EncodeFailed {
reason: String,
},
}
pub fn wrap_component(mut core_bytes: Vec<u8>, wit: &str) -> Result<Vec<u8>, ComponentWrapError> {
let mut resolve = Resolve::default();
let pkg = resolve
.push_str("formawasm-generated.wit", wit)
.map_err(|e| ComponentWrapError::WitParse {
reason: format!("{e:#}"),
})?;
let world = resolve
.select_world(&[pkg], Some(WORLD_NAME))
.map_err(|e| ComponentWrapError::WorldMissing {
reason: format!("{e:#}"),
})?;
embed_component_metadata(&mut core_bytes, &resolve, world, StringEncoding::UTF8).map_err(
|e| ComponentWrapError::EmbedFailed {
reason: format!("{e:#}"),
},
)?;
let mut encoder = ComponentEncoder::default()
.validate(true)
.module(&core_bytes)
.map_err(|e| ComponentWrapError::EncoderRejected {
reason: format!("{e:#}"),
})?;
encoder
.encode()
.map_err(|e| ComponentWrapError::EncodeFailed {
reason: format!("{e:#}"),
})
}