Skip to content

Commit 542b3a2

Browse files
authored
Merge pull request #149 from rustwasm/struct-fields
Generate accessors for public struct fields
2 parents f3c05e5 + ce31859 commit 542b3a2

File tree

6 files changed

+314
-76
lines changed

6 files changed

+314
-76
lines changed

crates/backend/src/ast.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ pub struct Function {
6868

6969
pub struct Struct {
7070
pub name: syn::Ident,
71+
pub fields: Vec<StructField>,
72+
}
73+
74+
pub struct StructField {
75+
pub name: syn::Ident,
76+
pub struct_name: syn::Ident,
77+
pub ty: syn::Type,
78+
pub getter: syn::Ident,
79+
pub setter: syn::Ident,
7180
}
7281

7382
pub struct Enum {
@@ -415,7 +424,7 @@ impl Program {
415424
pub fn shared(&self) -> shared::Program {
416425
shared::Program {
417426
exports: self.exports.iter().map(|a| a.shared()).collect(),
418-
structs: self.structs.iter().map(|a| a.name.as_ref().to_string()).collect(),
427+
structs: self.structs.iter().map(|a| a.shared()).collect(),
419428
enums: self.enums.iter().map(|a| a.shared()).collect(),
420429
imports: self.imports.iter().map(|a| a.shared()).collect(),
421430
version: shared::version(),
@@ -659,7 +668,47 @@ impl ImportType {
659668

660669
impl Struct {
661670
fn from(s: syn::ItemStruct, _opts: BindgenAttrs) -> Struct {
662-
Struct { name: s.ident }
671+
let mut fields = Vec::new();
672+
if let syn::Fields::Named(names) = s.fields {
673+
for field in names.named.iter() {
674+
match field.vis {
675+
syn::Visibility::Public(..) => {}
676+
_ => continue,
677+
}
678+
let name = match field.ident {
679+
Some(n) => n,
680+
None => continue,
681+
};
682+
let getter = shared::struct_field_get(s.ident.as_ref(), name.as_ref());
683+
let setter = shared::struct_field_set(s.ident.as_ref(), name.as_ref());
684+
fields.push(StructField {
685+
name,
686+
struct_name: s.ident,
687+
ty: field.ty.clone(),
688+
getter: getter.into(),
689+
setter: setter.into(),
690+
});
691+
}
692+
}
693+
Struct {
694+
name: s.ident,
695+
fields,
696+
}
697+
}
698+
699+
fn shared(&self) -> shared::Struct {
700+
shared::Struct {
701+
name: self.name.as_ref().to_string(),
702+
fields: self.fields.iter().map(|s| s.shared()).collect(),
703+
}
704+
}
705+
}
706+
707+
impl StructField {
708+
fn shared(&self) -> shared::StructField {
709+
shared::StructField {
710+
name: self.name.as_ref().to_string(),
711+
}
663712
}
664713
}
665714

crates/backend/src/codegen.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,65 @@ impl ToTokens for ast::Struct {
212212
}
213213
}
214214
}).to_tokens(tokens);
215+
216+
for field in self.fields.iter() {
217+
field.to_tokens(tokens);
218+
}
219+
}
220+
}
221+
222+
impl ToTokens for ast::StructField {
223+
fn to_tokens(&self, tokens: &mut Tokens) {
224+
let name = &self.name;
225+
let struct_name = &self.struct_name;
226+
let ty = &self.ty;
227+
let getter = &self.getter;
228+
let setter = &self.setter;
229+
let desc = syn::Ident::from(format!("__wbindgen_describe_{}", getter));
230+
(quote! {
231+
#[no_mangle]
232+
pub unsafe extern fn #getter(js: u32)
233+
-> <#ty as ::wasm_bindgen::convert::IntoWasmAbi>::Abi
234+
{
235+
use wasm_bindgen::__rt::{WasmRefCell, assert_not_null};
236+
use wasm_bindgen::convert::{GlobalStack, IntoWasmAbi};
237+
238+
fn assert_copy<T: Copy>(){}
239+
assert_copy::<#ty>();
240+
241+
let js = js as *mut WasmRefCell<#struct_name>;
242+
assert_not_null(js);
243+
let val = (*js).borrow().#name;
244+
<#ty as IntoWasmAbi>::into_abi(
245+
val,
246+
&mut GlobalStack::new(),
247+
)
248+
}
249+
250+
#[no_mangle]
251+
pub unsafe extern fn #setter(
252+
js: u32,
253+
val: <#ty as ::wasm_bindgen::convert::FromWasmAbi>::Abi,
254+
) {
255+
use wasm_bindgen::__rt::{WasmRefCell, assert_not_null};
256+
use wasm_bindgen::convert::{GlobalStack, FromWasmAbi};
257+
258+
let js = js as *mut WasmRefCell<#struct_name>;
259+
assert_not_null(js);
260+
let val = <#ty as FromWasmAbi>::from_abi(
261+
val,
262+
&mut GlobalStack::new(),
263+
);
264+
(*js).borrow_mut().#name = val;
265+
}
266+
267+
#[no_mangle]
268+
pub extern fn #desc() {
269+
use wasm_bindgen::describe::*;
270+
<#ty as WasmDescribe>::describe();
271+
272+
}
273+
}).to_tokens(tokens);
215274
}
216275
}
217276

crates/cli-support/src/js/js2rust.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub struct Js2Rust<'a, 'b: 'a> {
1111
rust_arguments: Vec<String>,
1212

1313
/// Arguments and their types to the JS shim.
14-
js_arguments: Vec<(String, String)>,
14+
pub js_arguments: Vec<(String, String)>,
1515

1616
/// Conversions that happen before we invoke the wasm function, such as
1717
/// converting a string to a ptr/length pair.
@@ -100,7 +100,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
100100
self
101101
}
102102

103-
fn argument(&mut self, arg: &Descriptor) {
103+
pub fn argument(&mut self, arg: &Descriptor) -> &mut Self {
104104
let i = self.arg_idx;
105105
self.arg_idx += 1;
106106
let name = format!("arg{}", i);
@@ -122,7 +122,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
122122
self.cx.require_internal_export("__wbindgen_free");
123123
}
124124
self.rust_arguments.push(format!("ptr{}", i));
125-
return
125+
return self
126126
}
127127

128128
if let Some(s) = arg.rust_struct() {
@@ -144,7 +144,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
144144
", i = i, arg = name));
145145
self.rust_arguments.push(format!("ptr{}", i));
146146
}
147-
return
147+
return self
148148
}
149149

150150
if arg.is_number() {
@@ -156,15 +156,15 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
156156
}
157157

158158
self.rust_arguments.push(name);
159-
return
159+
return self
160160
}
161161

162162
if arg.is_ref_anyref() {
163163
self.js_arguments.push((name.clone(), "any".to_string()));
164164
self.cx.expose_borrowed_objects();
165165
self.finally("stack.pop();");
166166
self.rust_arguments.push(format!("addBorrowedObject({})", name));
167-
return
167+
return self
168168
}
169169

170170
match *arg {
@@ -187,23 +187,24 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
187187
panic!("unsupported argument to rust function {:?}", arg)
188188
}
189189
}
190+
self
190191
}
191192

192-
fn ret(&mut self, ret: &Option<Descriptor>) {
193+
pub fn ret(&mut self, ret: &Option<Descriptor>) -> &mut Self {
193194
let ty = match *ret {
194195
Some(ref t) => t,
195196
None => {
196197
self.ret_ty = "void".to_string();
197198
self.ret_expr = format!("return RET;");
198-
return
199+
return self
199200
}
200201
};
201202

202203
if ty.is_ref_anyref() {
203204
self.ret_ty = "any".to_string();
204205
self.cx.expose_get_object();
205206
self.ret_expr = format!("return getObject(RET);");
206-
return
207+
return self
207208
}
208209

209210
if ty.is_by_ref() {
@@ -222,19 +223,19 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
222223
wasm.__wbindgen_free(ret, len * {});\n\
223224
return realRet;\n\
224225
", f, ty.size());
225-
return
226+
return self
226227
}
227228

228229
if let Some(name) = ty.rust_struct() {
229230
self.ret_ty = name.to_string();
230231
self.ret_expr = format!("return {name}.__construct(RET);", name = name);
231-
return
232+
return self
232233
}
233234

234235
if ty.is_number() {
235236
self.ret_ty = "number".to_string();
236237
self.ret_expr = format!("return RET;");
237-
return
238+
return self
238239
}
239240

240241
match *ty {
@@ -249,6 +250,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
249250
}
250251
_ => panic!("unsupported return from Rust to JS {:?}", ty),
251252
}
253+
self
252254
}
253255

254256
/// Generate the actual function.

0 commit comments

Comments
 (0)