Skip to content

Commit f7634e9

Browse files
committed
Support custom Rust types for list
Any type that implements `From<Vec<T>>`, `Into<Vec<T>>`, `Deref<Target=Vec<T>>`, and `Clone` can be used for a WIT type `list<T>` via the `with` option. The `Deref` and `Clone` impls are only required when the type is used as part of a non-canonical type.
1 parent 2a6d845 commit f7634e9

File tree

5 files changed

+153
-3
lines changed

5 files changed

+153
-3
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/rust/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ wit-bindgen = { path = '../guest-rust', features = ['async'] }
3434
test-helpers = { path = '../test-helpers' }
3535
# For use with the custom attributes test
3636
serde_json = "1"
37+
bytes = "1"
3738

3839
[features]
3940
serde = ['dep:serde', 'wit-bindgen-core/serde']

crates/rust/src/bindgen.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -670,11 +670,15 @@ impl Bindgen for FunctionBindgen<'_, '_> {
670670
let val = format!("vec{}", tmp);
671671
let ptr = format!("ptr{}", tmp);
672672
let len = format!("len{}", tmp);
673+
let vec = self.r#gen.path_to_vec();
673674
if realloc.is_none() {
674675
self.push_str(&format!("let {} = {};\n", val, operands[0]));
675676
} else {
676677
let op0 = operands.pop().unwrap();
677-
self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0));
678+
self.push_str(&format!(
679+
"let {} = <_ as Into<{vec}<_>>>::into({}).into_boxed_slice();\n",
680+
val, op0
681+
));
678682
}
679683
self.push_str(&format!("let {} = {}.as_ptr().cast::<u8>();\n", ptr, val));
680684
self.push_str(&format!("let {} = {}.len();\n", len, val));
@@ -691,7 +695,7 @@ impl Bindgen for FunctionBindgen<'_, '_> {
691695
self.push_str(&format!("let {} = {};\n", len, operands[1]));
692696
let vec = self.r#gen.path_to_vec();
693697
let result = format!(
694-
"{vec}::from_raw_parts({}.cast(), {1}, {1})",
698+
"<_ as From<{vec}<_>>>::from({vec}::from_raw_parts({}.cast(), {1}, {1}))",
695699
operands[0], len
696700
);
697701
results.push(result);

crates/rust/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,8 @@ impl RustWasm {
432432
}
433433

434434
self.src.push_str("mod _rt {\n");
435-
self.src.push_str("#![allow(dead_code, clippy::all)]\n");
435+
self.src
436+
.push_str("#![allow(dead_code, unused_imports, clippy::all)]\n");
436437
let mut emitted = IndexSet::new();
437438
while !self.rt_module.is_empty() {
438439
for item in mem::take(&mut self.rt_module) {

crates/rust/tests/codegen.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,140 @@ mod inline_and_path {
3131
generate_all,
3232
});
3333
}
34+
35+
#[allow(unused)]
36+
mod newtyped_list {
37+
use std::ops::Deref;
38+
39+
wit_bindgen::generate!({
40+
inline: r#"
41+
package test:newtyped-list;
42+
43+
interface byte {
44+
type typed-list-of-byte = list<u8>;
45+
type newtyped-list-of-byte = list<u8>;
46+
47+
record rec-of-lists {
48+
l: list<u8>,
49+
tl: typed-list-of-byte,
50+
nl: newtyped-list-of-byte,
51+
}
52+
53+
use-list-of-byte: func(l: list<u8>) -> list<u8>;
54+
use-typed-list-of-byte: func(tl: typed-list-of-byte) -> typed-list-of-byte;
55+
use-newtyped-list-of-byte: func(nl: newtyped-list-of-byte) -> newtyped-list-of-byte;
56+
use-rec-of-lists: func(t: rec-of-lists) -> rec-of-lists;
57+
}
58+
59+
interface noncopy-byte {
60+
// this will be new-typed by a non-copy struct
61+
type noncopy-byte = u8;
62+
63+
type newtyped-list-of-noncopy-byte = list<noncopy-byte>;
64+
type typed-list-of-noncopy-byte = list<noncopy-byte>;
65+
66+
record rec-of-lists-of-noncopy-byte {
67+
ntl: newtyped-list-of-noncopy-byte,
68+
tl: typed-list-of-noncopy-byte,
69+
l: list<noncopy-byte>,
70+
}
71+
72+
use-newtyped-list-of-noncopy-byte: func(nl: newtyped-list-of-noncopy-byte) -> newtyped-list-of-noncopy-byte;
73+
use-typed-list-of-noncopy-byte: func(tl: typed-list-of-noncopy-byte) -> typed-list-of-noncopy-byte;
74+
use-list-of-noncopy-byte: func(l: list<noncopy-byte>) -> list<noncopy-byte>;
75+
use-rec-of-lists-of-noncopy-byte: func(t: rec-of-lists-of-noncopy-byte) -> rec-of-lists-of-noncopy-byte;
76+
}
77+
78+
world test {
79+
import byte;
80+
export byte;
81+
import noncopy-byte;
82+
export noncopy-byte;
83+
}
84+
"#,
85+
with: {
86+
"test:newtyped-list/byte/newtyped-list-of-byte": crate::newtyped_list::NewtypedListOfByte,
87+
"test:newtyped-list/noncopy-byte/noncopy-byte": crate::newtyped_list::NoncopyByte,
88+
"test:newtyped-list/noncopy-byte/newtyped-list-of-noncopy-byte": crate::newtyped_list::NewtypedListofNoncopyByte,
89+
}
90+
});
91+
92+
#[derive(Debug, Clone)]
93+
pub struct NewtypedListOfByte(Vec<u8>);
94+
95+
impl From<Vec<u8>> for NewtypedListOfByte {
96+
fn from(value: Vec<u8>) -> Self {
97+
NewtypedListOfByte(value)
98+
}
99+
}
100+
101+
impl From<NewtypedListOfByte> for Vec<u8> {
102+
fn from(value: NewtypedListOfByte) -> Self {
103+
value.0
104+
}
105+
}
106+
107+
impl Deref for NewtypedListOfByte {
108+
type Target = Vec<u8>;
109+
110+
fn deref(&self) -> &Self::Target {
111+
&self.0
112+
}
113+
}
114+
115+
#[derive(Debug, Clone)]
116+
pub struct NoncopyByte(u8);
117+
118+
#[derive(Debug, Clone)]
119+
pub struct NewtypedListofNoncopyByte(Vec<NoncopyByte>);
120+
121+
impl From<Vec<NoncopyByte>> for NewtypedListofNoncopyByte {
122+
fn from(value: Vec<NoncopyByte>) -> Self {
123+
NewtypedListofNoncopyByte(value)
124+
}
125+
}
126+
127+
impl From<NewtypedListofNoncopyByte> for Vec<NoncopyByte> {
128+
fn from(value: NewtypedListofNoncopyByte) -> Self {
129+
value.0
130+
}
131+
}
132+
133+
impl Deref for NewtypedListofNoncopyByte {
134+
type Target = Vec<NoncopyByte>;
135+
136+
fn deref(&self) -> &Self::Target {
137+
&self.0
138+
}
139+
}
140+
}
141+
#[allow(unused)]
142+
mod retyped_list {
143+
use std::ops::Deref;
144+
145+
wit_bindgen::generate!({
146+
inline: r#"
147+
package test:retyped-list;
148+
149+
interface bytes {
150+
// this will be the `Bytes` type from the bytes crate
151+
type retyped-list-as-bytes = list<u8>;
152+
153+
record rec-bytes {
154+
rl: retyped-list-as-bytes,
155+
}
156+
157+
use-retyped-list-as-bytes: func(ri: retyped-list-as-bytes) -> retyped-list-as-bytes;
158+
use-rec-of-retyped-list-as-bytes: func(rl: retyped-list-as-bytes) -> retyped-list-as-bytes;
159+
}
160+
161+
world test {
162+
import bytes;
163+
export bytes;
164+
}
165+
"#,
166+
with: {
167+
"test:retyped-list/bytes/retyped-list-as-bytes": bytes::Bytes,
168+
}
169+
});
170+
}

0 commit comments

Comments
 (0)