Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
26 changes: 16 additions & 10 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)| {
Expand All @@ -279,23 +280,27 @@ 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()
);
}
}
}
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!(
Expand All @@ -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"
Expand All @@ -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(())
Expand Down
34 changes: 26 additions & 8 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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],
}
Expand Down Expand Up @@ -76,13 +77,6 @@ pub fn get_return_type(ret: &syn::ReturnType) -> Option<Type> {
pub fn extract_arg_info(sig: &Signature) -> (Option<ResourceFuncKind>, Vec<ArgInfo>) {
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(_) => {
Expand All @@ -103,6 +97,12 @@ pub fn extract_arg_info(sig: &Signature) -> (Option<ResourceFuncKind>, Vec<ArgIn
}
}
}
if sig.ident == "new"
&& let Some(Type::Path(path)) = get_return_type(&sig.output)
&& path.path.is_ident("Self")
{
kind = Some(ResourceFuncKind::Constructor);
}
(kind, arg_infos)
}

Expand Down Expand Up @@ -434,3 +434,21 @@ fn is_keyword(name: &str) -> 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<PackageId> {
let mut seen: BTreeMap<(String, String), Vec<PackageId>> = 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
}
Binary file added tests/wasi_http.wasm
Binary file not shown.