use anyhow::Context;
use cviz::model::{InterfaceType, TypeArena};
mod abi;
mod build;
mod filter;
mod func;
mod indices;
mod names;
#[cfg(test)]
mod tests;
use abi::WitBridge;
use build::build_adapter_bytes;
use filter::{extract_filtered_sections, find_handler_deps};
use func::extract_adapter_funcs;
#[allow(clippy::too_many_arguments)]
pub fn generate_tier1_adapter(
middleware_name: &str,
target_interface: &str,
middleware_interfaces: &[String],
interface_type: Option<&InterfaceType>,
splits_output_path: &str,
split_path: &str,
arena: &TypeArena,
) -> anyhow::Result<String> {
let iface_ty = interface_type.ok_or_else(|| {
anyhow::anyhow!(
"Type information for interface '{}' is required to generate a tier-1 adapter \
but was not available in the composition graph.",
target_interface
)
})?;
let bridge = WitBridge::from_cviz(arena);
let (funcs, layout) = extract_adapter_funcs(iface_ty, &bridge)?;
let has_before = middleware_interfaces.iter().any(|i| i.contains("/before"));
let has_after = middleware_interfaces.iter().any(|i| i.contains("/after"));
let has_blocking = middleware_interfaces
.iter()
.any(|i| i.contains("/blocking"));
let deps = find_handler_deps(split_path, target_interface)?;
if deps.not_found() {
anyhow::bail!(
"Split at '{}' neither imports nor exports interface '{}'. \
Please open an issue with a repro at https://github.com/ejrgilbert/splicer/issues",
split_path,
target_interface
);
}
let bytes = std::fs::read(split_path)
.with_context(|| format!("Failed to read split at '{split_path}'"))?;
let split = extract_filtered_sections(&bytes, &deps)?;
let bytes = build_adapter_bytes(
target_interface,
&funcs,
has_before,
has_after,
has_blocking,
arena,
iface_ty,
&split,
layout,
&bridge,
)?;
let out_path = format!(
"{splits_output_path}/splicer_adapter_{}_{}.wasm",
sanitize_name(middleware_name),
sanitize_name(target_interface)
);
std::fs::write(&out_path, &bytes)
.with_context(|| format!("Failed to write adapter component to '{}'", out_path))?;
Ok(out_path)
}
fn sanitize_name(s: &str) -> String {
s.chars()
.map(|c| if c.is_alphanumeric() { c } else { '_' })
.collect()
}