From 4cca295b90921b5c40330c70570a8238fdd57461 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:35:39 +0100 Subject: [PATCH 1/2] [hyperlight_component_*] Treat debug env var path as a template Previously, when using `HYPERLIGHT_COMPONENT_MACRO_DEBUG` to debug an issue with the Rust bindings generation, if the bindings generator macros were invoked multiple times during a single compile run, later invocations would overwrite the file specified by earlier invocations, leading to the earlier code getting lost and producing spurious compilation errors. This changes the relevant logic to support a template character (presently `#`) in the path, which is replaced by a version of the wit name for the world being worked on. Whilst there is still room for confusion between e.g. guest and host versions of the same world, this makes debugging a lot more possible. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- src/hyperlight_component_macro/src/lib.rs | 4 ++-- src/hyperlight_component_util/src/util.rs | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/hyperlight_component_macro/src/lib.rs b/src/hyperlight_component_macro/src/lib.rs index 3f2f19e49c..7db02403ee 100644 --- a/src/hyperlight_component_macro/src/lib.rs +++ b/src/hyperlight_component_macro/src/lib.rs @@ -77,7 +77,7 @@ pub fn host_bindgen(input: proc_macro::TokenStream) -> proc_macro::TokenStream { rtypes::emit_toplevel(s, &kebab_name, ct); host::emit_toplevel(s, &kebab_name, ct); }); - util::emit_decls(decls).into() + util::emit_decls(decls, &kebab_name).into() }) } @@ -106,7 +106,7 @@ pub fn guest_bindgen(input: proc_macro::TokenStream) -> proc_macro::TokenStream // stream directly and emitting an include!() pointing at a // temporary file, depending on whether the user has requested // a debug temporary file be created. - util::emit_decls(decls).into() + util::emit_decls(decls, &kebab_name).into() }) } diff --git a/src/hyperlight_component_util/src/util.rs b/src/hyperlight_component_util/src/util.rs index 4b23db88fc..037d76ddac 100644 --- a/src/hyperlight_component_util/src/util.rs +++ b/src/hyperlight_component_util/src/util.rs @@ -119,8 +119,12 @@ pub fn read_wit_type_from_file R>( /// Deal with `$HYPERLIGHT_COMPONENT_MACRO_DEBUG`: if it is present, /// save the given token stream (representing the result of /// macroexpansion) to the debug file and then return the token stream -pub fn emit_decls(decls: proc_macro2::TokenStream) -> proc_macro2::TokenStream { +pub fn emit_decls(decls: proc_macro2::TokenStream, for_kebab: &str) -> proc_macro2::TokenStream { if let Ok(dbg_out) = std::env::var("HYPERLIGHT_COMPONENT_MACRO_DEBUG") { + let fs_safe = for_kebab.replace("/", "_"); + #[cfg(windows)] + let fs_safe = fs_safe.replace(":", "+"); + let dbg_out = dbg_out.replace("#", &fs_safe); if let Ok(file) = syn::parse2(decls.clone()) { std::fs::write(&dbg_out, prettyplease::unparse(&file)).unwrap(); } else { From 9839de342b6713f0cb58cb1845f5f053eeef4de0 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:36:28 +0100 Subject: [PATCH 2/2] [hyperlight_component_*] Support reading WAT text components This is a minor change, bridging the gap between the already-supported textual WIT and binary formats. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com> --- Cargo.lock | 64 +++++++++++++++++--- src/hyperlight_component_macro/src/lib.rs | 9 ++- src/hyperlight_component_util/Cargo.toml | 1 + src/hyperlight_component_util/src/util.rs | 46 ++++++++++++--- src/tests/rust_guests/Cargo.lock | 72 ++++++++++++++++++++--- 5 files changed, 166 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd26b53ce1..9def63022c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1594,7 +1594,8 @@ dependencies = [ "quote", "syn 3.0.3", "tracing", - "wasmparser", + "wasmparser 0.255.0", + "wat", "wit-component", "wit-parser", ] @@ -4156,6 +4157,12 @@ version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -4337,7 +4344,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b524283fb5df62eec102ed0574838961bdd7ba5ac9c50d38e2756c51c971a42" dependencies = [ "leb128fmt", - "wasmparser", + "wasmparser 0.255.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.256.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1492381bfd5ea51c2a99a919b676662559925cb8d7490547ec2e14c1ad3eb1" +dependencies = [ + "leb128fmt", + "wasmparser 0.256.0", ] [[package]] @@ -4348,8 +4365,8 @@ checksum = "4d3b0da506f1b8514517972fbc47057b21273cb619290f51ea31403c157f896c" dependencies = [ "anyhow", "indexmap", - "wasm-encoder", - "wasmparser", + "wasm-encoder 0.255.0", + "wasmparser 0.255.0", ] [[package]] @@ -4365,6 +4382,39 @@ dependencies = [ "serde", ] +[[package]] +name = "wasmparser" +version = "0.256.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60bd825ffedc6cba8a642924ba7ae424afbc47811cffbcb7b92031ec24e59b4c" +dependencies = [ + "bitflags 2.13.1", + "indexmap", + "semver", +] + +[[package]] +name = "wast" +version = "256.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ad42723fc9222da007f05812a3249c9a4ee7af79d497fc2a2079579ad7efe6" +dependencies = [ + "bumpalo", + "leb128fmt", + "memchr", + "unicode-width", + "wasm-encoder 0.256.0", +] + +[[package]] +name = "wat" +version = "1.256.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37cc86c54d8011b3202e265bfebada440733ea3a788ffaf46d395f7d2fdeacfb" +dependencies = [ + "wast", +] + [[package]] name = "web-sys" version = "0.3.103" @@ -4587,9 +4637,9 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder", + "wasm-encoder 0.255.0", "wasm-metadata", - "wasmparser", + "wasmparser 0.255.0", "wit-parser", ] @@ -4609,7 +4659,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-ident", - "wasmparser", + "wasmparser 0.255.0", ] [[package]] diff --git a/src/hyperlight_component_macro/src/lib.rs b/src/hyperlight_component_macro/src/lib.rs index 7db02403ee..7e29ee983e 100644 --- a/src/hyperlight_component_macro/src/lib.rs +++ b/src/hyperlight_component_macro/src/lib.rs @@ -129,7 +129,7 @@ fn unknown_key_error(key: &Ident) -> syn::Error { syn::Error::new( key.span(), format!( - "unknown parameter '{}'; expected 'path', 'wit', 'wasm', 'inline', 'world', or 'world_name'", + "unknown parameter '{}'; expected 'path', 'wit', 'wasm', 'wat', 'inline', 'world', or 'world_name'", key ), ) @@ -146,6 +146,9 @@ fn source_from_key(key: &Ident, value: LitStr) -> Result { "wasm" => Ok(util::WitSource::Wasm(std::path::PathBuf::from( value.value(), ))), + "wat" => Ok(util::WitSource::Wat(std::path::PathBuf::from( + value.value(), + ))), "inline" => Ok(util::WitSource::Inline(value.value())), _ => Err(unknown_key_error(key)), } @@ -170,7 +173,7 @@ impl Parse for BindgenInputParams { let value: LitStr = content.parse()?; world_name = Some(value.value()); } - "path" | "wit" | "wasm" | "inline" => { + "path" | "wit" | "wasm" | "wat" | "inline" => { let value: LitStr = content.parse()?; if source.is_some() { return Err(syn::Error::new( @@ -193,7 +196,7 @@ impl Parse for BindgenInputParams { let value: LitStr = input.parse()?; match key.to_string().as_str() { "world" | "world_name" => world_name = Some(value.value()), - "path" | "wit" | "wasm" | "inline" => { + "path" | "wit" | "wasm" | "wat" | "inline" => { source = Some(source_from_key(&key, value)?); } _ => return Err(unknown_key_error(&key)), diff --git a/src/hyperlight_component_util/Cargo.toml b/src/hyperlight_component_util/Cargo.toml index d089473221..e0b7d4a459 100644 --- a/src/hyperlight_component_util/Cargo.toml +++ b/src/hyperlight_component_util/Cargo.toml @@ -16,6 +16,7 @@ name = "hyperlight_component_util" [dependencies] wasmparser = { version = "0.255.0" } +wat = { version = "1.256.0" } wit-component = { version = "0.255.0" } wit-parser = { version = "0.255.0" } quote = { version = "1.0.45" } diff --git a/src/hyperlight_component_util/src/util.rs b/src/hyperlight_component_util/src/util.rs index 037d76ddac..45836f3348 100644 --- a/src/hyperlight_component_util/src/util.rs +++ b/src/hyperlight_component_util/src/util.rs @@ -21,6 +21,7 @@ use crate::etypes; #[derive(Debug)] pub enum WitSource { Wasm(std::path::PathBuf), + Wat(std::path::PathBuf), Wit(std::path::PathBuf), Inline(String), } @@ -44,6 +45,16 @@ impl WitSource { } bytes } + Self::Wat(path) => { + let path = manifest_path(&path); + let bytes = wat::parse_file(&path).unwrap_or_else(|err| { + panic!("failed to read wat input '{}': {err:#}", path.display()); + }); + if !wasmparser::Parser::is_component(&bytes) { + panic!("wat input '{}' is not a wasm component", path.display()); + } + bytes + } Self::Wit(path) => { let path = manifest_path(&path); let mut resolve = wit_parser::Resolve::default(); @@ -59,14 +70,33 @@ impl WitSource { }) } Self::Inline(contents) => { - let mut resolve = wit_parser::Resolve::default(); - let package = resolve - .push_str("inline.wit", &contents) - .unwrap_or_else(|err| panic!("failed to parse inline WIT input: {err:#}")); - - wit_component::encode(&resolve, package).unwrap_or_else(|err| { - panic!("failed to encode inline WIT input as a wasm component type: {err:#}") - }) + match wat::Detect::from_bytes(&contents) { + wat::Detect::WasmBinary => { + panic!("inline component type looks like a binary!") + } + wat::Detect::WasmText => { + let bytes = wat::parse_str(&contents).unwrap_or_else(|err| { + panic!("failed to read inline wat input: {err:#}") + }); + if !wasmparser::Parser::is_component(&bytes) { + panic!("inline wat input is not a wasm component"); + } + bytes + } + wat::Detect::Unknown => { + // It's probably WIT + let mut resolve = wit_parser::Resolve::default(); + let package = + resolve + .push_str("inline.wit", &contents) + .unwrap_or_else(|err| { + panic!("failed to parse inline WIT input: {err:#}") + }); + wit_component::encode(&resolve, package).unwrap_or_else(|err| { + panic!("failed to encode inline WIT input as a wasm component type: {err:#}") + }) + } + } } } } diff --git a/src/tests/rust_guests/Cargo.lock b/src/tests/rust_guests/Cargo.lock index 189ce58caa..ffb8271dfc 100644 --- a/src/tests/rust_guests/Cargo.lock +++ b/src/tests/rust_guests/Cargo.lock @@ -88,6 +88,12 @@ dependencies = [ "spin 0.10.0", ] +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + [[package]] name = "bytemuck" version = "1.25.0" @@ -268,7 +274,8 @@ dependencies = [ "quote", "syn 3.0.2", "tracing", - "wasmparser", + "wasmparser 0.255.0", + "wat", "wit-component", "wit-parser", ] @@ -759,6 +766,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "utf8parse" version = "0.2.2" @@ -772,7 +785,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b524283fb5df62eec102ed0574838961bdd7ba5ac9c50d38e2756c51c971a42" dependencies = [ "leb128fmt", - "wasmparser", + "wasmparser 0.255.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.256.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1492381bfd5ea51c2a99a919b676662559925cb8d7490547ec2e14c1ad3eb1" +dependencies = [ + "leb128fmt", + "wasmparser 0.256.0", ] [[package]] @@ -783,8 +806,8 @@ checksum = "4d3b0da506f1b8514517972fbc47057b21273cb619290f51ea31403c157f896c" dependencies = [ "anyhow", "indexmap", - "wasm-encoder", - "wasmparser", + "wasm-encoder 0.255.0", + "wasmparser 0.255.0", ] [[package]] @@ -800,6 +823,39 @@ dependencies = [ "serde", ] +[[package]] +name = "wasmparser" +version = "0.256.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60bd825ffedc6cba8a642924ba7ae424afbc47811cffbcb7b92031ec24e59b4c" +dependencies = [ + "bitflags 2.13.0", + "indexmap", + "semver", +] + +[[package]] +name = "wast" +version = "256.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ad42723fc9222da007f05812a3249c9a4ee7af79d497fc2a2079579ad7efe6" +dependencies = [ + "bumpalo", + "leb128fmt", + "memchr", + "unicode-width", + "wasm-encoder 0.256.0", +] + +[[package]] +name = "wat" +version = "1.256.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37cc86c54d8011b3202e265bfebada440733ea3a788ffaf46d395f7d2fdeacfb" +dependencies = [ + "wast", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -837,9 +893,9 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder", + "wasm-encoder 0.255.0", "wasm-metadata", - "wasmparser", + "wasmparser 0.255.0", "wit-parser", ] @@ -859,7 +915,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-ident", - "wasmparser", + "wasmparser 0.255.0", ] [[package]] @@ -877,4 +933,4 @@ dependencies = [ name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" \ No newline at end of file +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"