diff --git a/Makefile b/Makefile index 2ca7992..66d4b1d 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ test: test-fuzz test-record test-dialog test-fuzz: $(MAKE) run-fuzz WASM=tests/calculator.wasm + $(MAKE) run-fuzz WASM=tests/wasi_http.wasm # build-only test target/release/proxy-component instrument -m fuzz tests/rust.wasm target/release/proxy-component instrument -m fuzz tests/go.wasm @@ -28,6 +29,8 @@ test-record: # build-only test target/release/proxy-component instrument -m record tests/calculator.wasm target/release/proxy-component instrument -m replay tests/calculator.wasm + target/release/proxy-component instrument -m record tests/wasi_http.wasm + target/release/proxy-component instrument -m replay tests/wasi_http.wasm test-dialog: rm tests/composed.wasm || true diff --git a/src/ast.rs b/src/ast.rs index 50f2ace..1ba7298 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -266,6 +266,7 @@ impl<'a> Opt<'a> { pub fn generate_wrapped_wits(&self, dir: &std::path::Path) -> Result<()> { let mut resolve = Resolve::default(); let (main_id, _files) = resolve.push_dir(dir)?; + let has_version = package_with_version(&resolve); // Generate conversion interface. Not updating resolve to avoid deep cloning the packages. let mut resources = BTreeMap::new(); for (_, iface) in resolve.interfaces.iter().filter(|(_, iface)| { @@ -279,13 +280,17 @@ impl<'a> Opt<'a> { if matches!(ty.kind, TypeDefKind::Resource) { let mut resource = format!("{}:{}/{}", pkg_name.namespace, pkg_name.name, iface_name); - let resource_no_ver = resource.clone(); + let mut bindgen_name = format!("{}:{}", pkg_name.namespace, pkg_name.name); if let Some(ver) = &pkg_name.version { resource.push_str(&format!("@{ver}")); + if has_version.contains(&pkg_id) { + bindgen_name.push_str(&format!("{ver}")); + } } + bindgen_name.push_str(&format!("/{}", iface_name)); assert!( resources - .insert(*ty_id, (ty_name, resource, resource_no_ver)) + .insert(*ty_id, (ty_name, resource, bindgen_name)) .is_none() ); } @@ -293,9 +298,9 @@ impl<'a> Opt<'a> { } let mut out = Source::default(); out.push_str("package proxy:conversion;\ninterface conversion {"); - for (resource, iface, iface_no_ver) in resources.into_values() { + for (resource, iface, bindgen_name) in resources.into_values() { use heck::ToKebabCase; - let func_name = format!("{iface_no_ver}-{resource}").to_kebab_case(); + let func_name = format!("{bindgen_name}-{resource}").to_kebab_case(); match self.mode { Mode::Record => { out.push_str(&format!( @@ -313,7 +318,7 @@ impl<'a> Opt<'a> { } Mode::Replay | Mode::Fuzz | Mode::Dialog => { // Add a magic separator so that codegen::generate_conversion_func can recover the resource name - let magic_name = format!("{iface_no_ver}-magic42-{resource}").to_kebab_case(); + let magic_name = format!("{bindgen_name}-magic42-{resource}").to_kebab_case(); out.push_str(&format!("\nuse {iface}.{{{resource} as {func_name}}};\n")); out.push_str(&format!( "get-mock-{magic_name}: func(handle: u32) -> {func_name};\n" @@ -339,11 +344,12 @@ impl<'a> Opt<'a> { for (id, pkg) in resolve.packages.iter().filter(|(id, _)| *id != main_id) { let mut printer = WitPrinter::default(); printer.print_package(&resolve, id, true)?; - std::fs::write( - dir.join("deps") - .join(format!("wrapped-{}.wit", pkg.name.name)), - printer.output.to_string(), - )?; + let filename = if let Some(ver) = &pkg.name.version { + format!("wrapped-{}@{}.wit", pkg.name.name, ver) + } else { + format!("wrapped-{}.wit", pkg.name.name) + }; + std::fs::write(dir.join("deps").join(&filename), printer.output.to_string())?; } } Ok(()) diff --git a/src/util.rs b/src/util.rs index 0f7068b..435e397 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,8 +2,9 @@ use crate::codegen::{self, ItemFlag, TypeInfo}; use heck::ToKebabCase; use quote::ToTokens; use std::borrow::Cow; +use std::collections::{BTreeMap, BTreeSet}; use syn::{FnArg, Ident, Item, Signature, Type, Visibility, parse_quote, visit_mut::VisitMut}; - +use wit_bindgen_core::wit_parser::{PackageId, Resolve}; pub struct FullTypePath<'a> { pub module_path: &'a [String], } @@ -76,13 +77,6 @@ pub fn get_return_type(ret: &syn::ReturnType) -> Option { pub fn extract_arg_info(sig: &Signature) -> (Option, Vec) { let mut kind = None; let mut arg_infos = Vec::new(); - if sig.ident == "new" - && sig.inputs.is_empty() - && let Some(Type::Path(path)) = get_return_type(&sig.output) - && path.path.is_ident("Self") - { - return (Some(ResourceFuncKind::Constructor), arg_infos); - } for arg in sig.inputs.iter() { match arg { FnArg::Receiver(_) => { @@ -103,6 +97,12 @@ pub fn extract_arg_info(sig: &Signature) -> (Option, Vec bool { | "async" ) } + +/// Return the set of package ids that will have version suffix in the wit-bindgen +/// Use the same logic as in https://github.com/bytecodealliance/wit-bindgen/blob/main/crates/core/src/path.rs +pub fn package_with_version(resolve: &Resolve) -> BTreeSet { + let mut seen: BTreeMap<(String, String), Vec> = BTreeMap::new(); + for (id, p) in resolve.packages.iter() { + seen.entry((p.name.namespace.clone(), p.name.name.clone())) + .or_default() + .push(id); + } + let mut res = BTreeSet::new(); + for (_, ids) in seen { + if ids.len() > 1 { + res.extend(ids); + } + } + res +} diff --git a/tests/wasi_http.wasm b/tests/wasi_http.wasm new file mode 100644 index 0000000..1db7435 Binary files /dev/null and b/tests/wasi_http.wasm differ