From f41ad1fe8a511efdd2dabeec04ba1c5a0ad8e05e Mon Sep 17 00:00:00 2001 From: azdle Date: Wed, 26 Nov 2025 12:23:12 -0600 Subject: [PATCH 1/2] Support custom Rust types for `list` Any type that implements `From>`, `Into>` can be used for a WIT type `list` via the `with` option. --- crates/rust/src/bindgen.rs | 8 ++++++-- crates/rust/src/lib.rs | 3 ++- crates/rust/tests/codegen.rs | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index b83da0058..0e3007ab6 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -670,11 +670,15 @@ impl Bindgen for FunctionBindgen<'_, '_> { let val = format!("vec{}", tmp); let ptr = format!("ptr{}", tmp); let len = format!("len{}", tmp); + let vec = self.r#gen.path_to_vec(); if realloc.is_none() { self.push_str(&format!("let {} = {};\n", val, operands[0])); } else { let op0 = operands.pop().unwrap(); - self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0)); + self.push_str(&format!( + "let {} = <_ as Into<{vec}<_>>>::into({}).into_boxed_slice();\n", + val, op0 + )); } self.push_str(&format!("let {} = {}.as_ptr().cast::();\n", ptr, val)); self.push_str(&format!("let {} = {}.len();\n", len, val)); @@ -691,7 +695,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.push_str(&format!("let {} = {};\n", len, operands[1])); let vec = self.r#gen.path_to_vec(); let result = format!( - "{vec}::from_raw_parts({}.cast(), {1}, {1})", + "<_ as From<{vec}<_>>>::from({vec}::from_raw_parts({}.cast(), {1}, {1}))", operands[0], len ); results.push(result); diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index fd92b1953..99c14a740 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -432,7 +432,8 @@ impl RustWasm { } self.src.push_str("mod _rt {\n"); - self.src.push_str("#![allow(dead_code, clippy::all)]\n"); + self.src + .push_str("#![allow(dead_code, unused_imports, clippy::all)]\n"); let mut emitted = IndexSet::new(); while !self.rt_module.is_empty() { for item in mem::take(&mut self.rt_module) { diff --git a/crates/rust/tests/codegen.rs b/crates/rust/tests/codegen.rs index e84b4b368..1dff2df22 100644 --- a/crates/rust/tests/codegen.rs +++ b/crates/rust/tests/codegen.rs @@ -31,3 +31,43 @@ mod inline_and_path { generate_all, }); } + +#[allow(unused)] +mod newtyped_list { + wit_bindgen::generate!({ + inline: r#" + package test:newtyped-list; + + interface ntl { + type newtyped-list = list; + type typed-list = list; + + use-newtyped-list: func(nl: newtyped-list) -> newtyped-list; + use-typed-list: func(tl: typed-list) -> typed-list; + use-list: func(l: list) -> list; + } + + world test { + import ntl; + export ntl; + } + "#, + with: { + "test:newtyped-list/ntl/newtyped-list": crate::newtyped_list::NewtypedList, + } + }); + + struct NewtypedList(Vec); + + impl From> for NewtypedList { + fn from(value: Vec) -> Self { + NewtypedList(value) + } + } + + impl From for Vec { + fn from(value: NewtypedList) -> Self { + value.0 + } + } +} From 8368d748a4fef4495870f94b2dfae09c0d3c617d Mon Sep 17 00:00:00 2001 From: azdle Date: Thu, 4 Dec 2025 14:53:45 -0600 Subject: [PATCH 2/2] wip: test more list types --- Cargo.lock | 7 +++ crates/rust/Cargo.toml | 1 + crates/rust/src/bindgen.rs | 2 +- crates/rust/tests/codegen.rs | 92 +++++++++++++++++++++++++++++++++++- 4 files changed, 100 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b4a4ac0a..ee0bb54e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,6 +94,12 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + [[package]] name = "cfg-if" version = "1.0.3" @@ -1338,6 +1344,7 @@ name = "wit-bindgen-rust" version = "0.48.1" dependencies = [ "anyhow", + "bytes", "clap", "futures", "heck", diff --git a/crates/rust/Cargo.toml b/crates/rust/Cargo.toml index ca96966ae..d4e6c88b9 100644 --- a/crates/rust/Cargo.toml +++ b/crates/rust/Cargo.toml @@ -34,6 +34,7 @@ wit-bindgen = { path = '../guest-rust', features = ['async'] } test-helpers = { path = '../test-helpers' } # For use with the custom attributes test serde_json = "1" +bytes = "*" [features] serde = ['dep:serde', 'wit-bindgen-core/serde'] diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index 0e3007ab6..a776f99df 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -814,7 +814,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!(self.src, "let e{tmp} = {body};"); uwriteln!(self.src, "{result}.push(e{tmp});"); uwriteln!(self.src, "}}"); - results.push(result); + results.push(format!("<_ as From>>::from({result})")); let dealloc = self.r#gen.path_to_cabi_dealloc(); self.push_str(&format!( "{dealloc}({base}, {len} * {size}, {align});\n", diff --git a/crates/rust/tests/codegen.rs b/crates/rust/tests/codegen.rs index 1dff2df22..ff433c79f 100644 --- a/crates/rust/tests/codegen.rs +++ b/crates/rust/tests/codegen.rs @@ -34,6 +34,8 @@ mod inline_and_path { #[allow(unused)] mod newtyped_list { + use std::ops::Deref; + wit_bindgen::generate!({ inline: r#" package test:newtyped-list; @@ -47,17 +49,60 @@ mod newtyped_list { use-list: func(l: list) -> list; } + interface ntl-bytes { + type newtyped-bytes-list = list; + type typed-bytes-list = list; + + use-newtyped-bytes-list: func(nl: newtyped-bytes-list) -> newtyped-bytes-list; + use-typed-bytes-list: func(tl: typed-bytes-list) -> typed-bytes-list; + use-bytes-list: func(l: list) -> list; + } + + interface ntl-noncopy { + // this will be new-typed by a non-copy struct + type noncopy-byte = u8; + + type newtyped-noncopy-list = list; + type typed-noncopy-list = list; + + use-newtyped-noncopy-list: func(nl: newtyped-noncopy-list) -> newtyped-noncopy-list; + use-typed-noncopy-list: func(tl: typed-noncopy-list) -> typed-noncopy-list; + use-noncopy-list: func(l: list) -> list; + } + + interface ntl-noncanonical { + // tuples are non-canonical, but can implement copy + type noncanonical = tuple; + + type newtyped-noncanonical-list = list; + type typed-noncanonical-list = list; + + use-newtyped-noncanonical-list: func(nl: newtyped-noncanonical-list) -> newtyped-noncanonical-list; + use-typed-noncanonical-list: func(tl: typed-noncanonical-list) -> typed-noncanonical-list; + use-noncanonical-list: func(l: list) -> list; + } + world test { import ntl; export ntl; + import ntl-bytes; + export ntl-bytes; + import ntl-noncopy; + export ntl-noncopy; + import ntl-noncanonical; + export ntl-noncanonical; } "#, with: { "test:newtyped-list/ntl/newtyped-list": crate::newtyped_list::NewtypedList, + "test:newtyped-list/ntl-bytes/newtyped-bytes-list": bytes::Bytes, + "test:newtyped-list/ntl-noncopy/noncopy-byte": crate::newtyped_list::NoncopyByte, + "test:newtyped-list/ntl-noncopy/newtyped-noncopy-list": crate::newtyped_list::NewtypedNoncopyList, + "test:newtyped-list/ntl-noncanonical/newtyped-noncanonical-list": crate::newtyped_list::NewtypedNoncanonicalList, } }); - struct NewtypedList(Vec); + pub struct NewtypedList(Vec); impl From> for NewtypedList { fn from(value: Vec) -> Self { @@ -70,4 +115,49 @@ mod newtyped_list { value.0 } } + + pub struct NoncopyByte(u8); + pub struct NewtypedNoncopyList(Vec); + + impl From> for NewtypedNoncopyList { + fn from(value: Vec) -> Self { + NewtypedNoncopyList(value) + } + } + + impl From for Vec { + fn from(value: NewtypedNoncopyList) -> Self { + value.0 + } + } + + impl Deref for NewtypedNoncopyList { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + pub struct NewtypedNoncanonicalList(Vec<(u8, u8)>); + + impl From> for NewtypedNoncanonicalList { + fn from(value: Vec<(u8, u8)>) -> Self { + NewtypedNoncanonicalList(value) + } + } + + impl From for Vec<(u8, u8)> { + fn from(value: NewtypedNoncanonicalList) -> Self { + value.0 + } + } + + impl Deref for NewtypedNoncanonicalList { + type Target = Vec<(u8, u8)>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } }