From 3abf747a648eb64747245573aede9a2e194e0af5 Mon Sep 17 00:00:00 2001 From: Scott Andrews Date: Mon, 8 Jun 2026 21:53:04 -0400 Subject: [PATCH] feat(rust): Expose merge_structurally_equal_types The generate! macro now exposes `merge_structurally_equal_types`. This functionality was previously only available via the `--merge-structurally-equal-types` CLI flag. The underlying functionality is unchanged. Signed-off-by: Scott Andrews --- crates/guest-rust/macro/src/lib.rs | 9 ++++ crates/guest-rust/src/lib.rs | 9 ++++ crates/rust/tests/codegen.rs | 66 ++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/crates/guest-rust/macro/src/lib.rs b/crates/guest-rust/macro/src/lib.rs index e5ae0b0ef..acf97ad53 100644 --- a/crates/guest-rust/macro/src/lib.rs +++ b/crates/guest-rust/macro/src/lib.rs @@ -168,6 +168,9 @@ impl Parse for Config { Opt::EnableMethodChaining(enable) => { opts.enable_method_chaining = enable.value(); } + Opt::MergeStructurallyEqualTypes(enable) => { + opts.merge_structurally_equal_types = Some(Some(enable.value())) + } } } } else { @@ -322,6 +325,7 @@ mod kw { syn::custom_keyword!(imports); syn::custom_keyword!(debug); syn::custom_keyword!(enable_method_chaining); + syn::custom_keyword!(merge_structurally_equal_types); } #[derive(Clone)] @@ -403,6 +407,7 @@ enum Opt { Async(AsyncFilterSet, Span), Debug(syn::LitBool), EnableMethodChaining(syn::LitBool), + MergeStructurallyEqualTypes(syn::LitBool), } impl Parse for Opt { @@ -586,6 +591,10 @@ impl Parse for Opt { } Ok(Opt::Async(set, span)) } + } else if l.peek(kw::merge_structurally_equal_types) { + input.parse::()?; + input.parse::()?; + Ok(Opt::MergeStructurallyEqualTypes(input.parse()?)) } else { Err(l.error()) } diff --git a/crates/guest-rust/src/lib.rs b/crates/guest-rust/src/lib.rs index a98cc7a0b..1be14bead 100644 --- a/crates/guest-rust/src/lib.rs +++ b/crates/guest-rust/src/lib.rs @@ -865,6 +865,15 @@ extern crate std; /// // returning `-> &Self`, to permit method chaining (e.g. for builder). /// // This expectation is also imposed on exports. /// enable_method_chaining: true, +/// +/// // Find all structurally equal types and only generate one type +/// // definition for each equivalence class. +/// // +/// // Other types in the same class will be type aliases to the generated +/// // type. This avoids clone when converting between types that are +/// // structurally equal, which is useful when import and export the same +/// // interface. +/// merge_structurally_equal_types: true, /// }); /// ``` /// diff --git a/crates/rust/tests/codegen.rs b/crates/rust/tests/codegen.rs index a6df22cf9..acc068a96 100644 --- a/crates/rust/tests/codegen.rs +++ b/crates/rust/tests/codegen.rs @@ -235,3 +235,69 @@ mod method_chaining { enable_method_chaining: true }); } + +#[allow(unused, reason = "testing codegen, not functionality")] +mod merge_structurally_equal_types { + wit_bindgen::generate!({ + inline: r#" + package test:merge-structurally-equal-types; + + interface blag { + variant kind1 { a, b(u64), c } + variant kind2 { a, b(u64), c } + record kind3 { a: input-stream } + record kind4 { a: input-stream } + record tree { l: t1, r: t1 } + record t1 { l: t2, r: t2 } + record t2 { l: t3, r: t3 } + record t3 { l: kind1, r: kind2 } + record t-stream { tree: tree, %stream: option> } + resource input-stream { + read: func(len: u64) -> list; + } + f: func(x: kind1) -> kind2; + g: func(x: kind3) -> kind4; + h: func(x: t-stream) -> tree; + } + + interface blah { + use blag.{input-stream, kind4, t-stream}; + variant kind5 { a, b(u64), c } + variant kind6 { a, c, b(u64) } + record kind7 { a: borrow } + record tt { l: t2, r: t2 } + record t1 { l: t3, r: t3 } + record t2 { l: t1, r: t1 } + record t3 { l: kind5, r: kind5 } + variant custom-result { ok(tt), err } + f: func(x: kind6) -> kind5; + g: func(x: kind7) -> kind4; + h: func(x: t-stream) -> custom-result; + + record r1 { a: u8 } + type a1 = u8; + record r2 { a: a1 } + alias-type: func(x: r1) -> r2; + } + + interface resources { + resource r1; + type r2 = r1; + + record t1 { a: r1 } + record t2 { a: r2 } + alias-own: func(x: t1) -> t2; + alias-aggregate: func(x: option) -> option; + } + + world proxy { + import blag; + export blag; + import blah; + export blah; + } + "#, + generate_all, + merge_structurally_equal_types: true + }); +}