mod assemble;
mod bindgen;
mod bindings_index;
mod build;
mod emit_method;
mod emit_wit_typed;
mod ir;
pub(crate) mod target_wit;
pub use assemble::{assemble_cargo_toml, assemble_lib_rs, CargoTomlInputs, WrapperCrateInputs};
pub use bindgen::run_wit_bindgen_rust;
pub use bindings_index::build_bindings_index;
pub use build::{build_wrapper, BuildConfig};
pub use emit_method::{emit_guest, EmittedGuest};
pub use emit_wit_typed::emit_wit_typed_impls;
#[allow(unused_imports)]
pub use ir::{build_ir, NamedKind, NamedType, WitTypeRef, WrapperIR};
pub use target_wit::{target_wit_for_codegen, TargetWit};
use anyhow::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Behavior {
Transform,
Virtualize,
}
pub fn generate_wrapper_crate(input: &GenerateWrapperInput<'_>) -> Result<WrapperCrate> {
let (resolve, world_id, bindings_src) =
run_wit_bindgen_rust(input.target_wit, input.world_name)?;
let bindings = build_bindings_index(&bindings_src)?;
let ir = build_ir(&resolve, world_id, &bindings)?;
let user_impls = emit_wit_typed_impls(&ir.types);
let args_impls = emit_wit_typed_impls(&ir.args_records);
let witty_impls: Vec<_> = user_impls.into_iter().chain(args_impls).collect();
let guests: Vec<EmittedGuest> = bindings
.guest_traits
.iter()
.map(|g| emit_guest(g, input.interface_qualified_name, input.behavior, &ir))
.collect();
let lib_rs = assemble_lib_rs(&WrapperCrateInputs {
bindings_src: &bindings_src,
witty_impls: &witty_impls,
guests: &guests,
behavior: input.behavior,
strategy_crate_name: input.strategy_crate_name,
strategy_type: input.strategy_type,
})?;
let crate_name =
make_wrapper_crate_name(input.interface_qualified_name, input.strategy_crate_name);
let cargo_toml = assemble_cargo_toml(&CargoTomlInputs {
crate_name: &crate_name,
strategy_crate_name: input.strategy_crate_name,
strategy_crate_path: input.strategy_crate_path,
splicer_tool_sdk_version: input.splicer_tool_sdk_version,
});
Ok(WrapperCrate {
crate_name,
lib_rs,
cargo_toml,
})
}
pub struct GenerateWrapperInput<'a> {
pub target_wit: &'a str,
pub world_name: Option<&'a str>,
pub interface_qualified_name: &'a str,
pub behavior: Behavior,
pub strategy_crate_name: &'a str,
pub strategy_crate_path: &'a str,
pub strategy_type: &'a str,
pub splicer_tool_sdk_version: &'a str,
}
pub struct WrapperCrate {
pub crate_name: String,
pub lib_rs: String,
pub cargo_toml: String,
}
fn make_wrapper_crate_name(interface: &str, strategy: &str) -> String {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let sanitize = |s: &str| -> String {
s.chars()
.map(|c| {
if c.is_ascii_alphanumeric() {
c.to_ascii_lowercase()
} else {
'_'
}
})
.collect()
};
let mut h = DefaultHasher::new();
interface.hash(&mut h);
strategy.hash(&mut h);
let suffix = format!("{:08x}", h.finish() as u32);
format!(
"splicer_wrapper_{}_{}_{}",
sanitize(interface),
sanitize(strategy),
suffix,
)
}
#[cfg(test)]
mod tests;