mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 02:00:51 +00:00
Implement getter/setter bindings
This commit is contained in:
parent
e72f9e176f
commit
9183236522
39
DESIGN.md
39
DESIGN.md
@ -669,12 +669,20 @@ extern {
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
fn set(this: &Bar, val: i32);
|
||||
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn property(this: &Bar) -> i32;
|
||||
|
||||
#[wasm_bindgen(method, setter)]
|
||||
fn set_property(this: &Bar, val: i32);
|
||||
}
|
||||
|
||||
fn run() {
|
||||
let bar = Bar::new(Bar::another_function());
|
||||
let x = bar.get();
|
||||
bar.set(x + 3);
|
||||
|
||||
bar.set_property(bar.property() + 6);
|
||||
}
|
||||
```
|
||||
|
||||
@ -726,6 +734,16 @@ const set_shim = Bar.prototype.set;
|
||||
export function __wbg_s_Bar_set(ptr, arg0) {
|
||||
set_shim.call(getObject(ptr), arg0)
|
||||
}
|
||||
|
||||
const property_shim = Object.getOwnPropertyDescriptor(Bar.prototype, 'property').get;
|
||||
export function __wbg_s_Bar_property(ptr) {
|
||||
return property_shim.call(getObject(ptr));
|
||||
}
|
||||
|
||||
const set_property_shim = Object.getOwnPropertyDescriptor(Bar.prototype, 'property').set;
|
||||
export function __wbg_s_Bar_set_property(ptr, arg0) {
|
||||
set_property_shim.call(getObject(ptr), arg0)
|
||||
}
|
||||
```
|
||||
|
||||
Like when importing functions from JS we can see a bunch of shims are generated
|
||||
@ -787,6 +805,27 @@ impl Bar {
|
||||
__wbg_s_Bar_set(ptr, val);
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self) -> i32 {
|
||||
extern {
|
||||
fn __wbg_s_Bar_property(ptr: u32) -> i32;
|
||||
}
|
||||
unsafe {
|
||||
let ptr = self.obj.__get_idx();
|
||||
let ret = __wbg_s_Bar_property(ptr);
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
fn set_property(&self, val: i32) {
|
||||
extern {
|
||||
fn __wbg_s_Bar_set_property(ptr: u32, val: i32);
|
||||
}
|
||||
unsafe {
|
||||
let ptr = self.obj.__get_idx();
|
||||
__wbg_s_Bar_set_property(ptr, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WasmBoundary for Bar {
|
||||
|
@ -95,7 +95,8 @@ pub fn project() -> Project {
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": true,
|
||||
"alwaysStrict": true,
|
||||
"strict": true
|
||||
"strict": true,
|
||||
"target": "es5"
|
||||
}
|
||||
}
|
||||
"#.to_string()),
|
||||
|
@ -957,23 +957,39 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
||||
let invoc_args = invoc_args.join(", ");
|
||||
let function_name = &import.function.name;
|
||||
let invoc = match import.class {
|
||||
Some(ref class) if import.method => {
|
||||
self.cx.globals.push_str(&format!("
|
||||
const {}_target = {}.prototype.{};
|
||||
", name, class, function_name));
|
||||
format!("{}_target.call({})", name, invoc_args)
|
||||
}
|
||||
Some(ref class) if import.js_new => {
|
||||
format!("new {}({})", class, invoc_args)
|
||||
format!("new {}", class)
|
||||
}
|
||||
Some(ref class) if import.method => {
|
||||
let target = if let Some(ref g) = import.getter {
|
||||
format!(
|
||||
"Object.getOwnPropertyDescriptor({}.prototype, '{}').get;",
|
||||
class,
|
||||
g,
|
||||
)
|
||||
} else if let Some(ref s) = import.setter {
|
||||
format!(
|
||||
"Object.getOwnPropertyDescriptor({}.prototype, '{}').set;",
|
||||
class,
|
||||
s,
|
||||
)
|
||||
} else {
|
||||
format!("{}.prototype.{}", class, function_name)
|
||||
};
|
||||
self.cx.globals.push_str(&format!("
|
||||
const {}_target = {};
|
||||
", name, target));
|
||||
format!("{}_target.call", name)
|
||||
}
|
||||
Some(ref class) => {
|
||||
self.cx.globals.push_str(&format!("
|
||||
const {}_target = {}.{};
|
||||
", name, class, function_name));
|
||||
format!("{}_target({})", name, invoc_args)
|
||||
format!("{}_target", name)
|
||||
}
|
||||
None => format!("{}({})", function_name, invoc_args),
|
||||
None => function_name.to_string(),
|
||||
};
|
||||
let invoc = format!("{}({})", invoc, invoc_args);
|
||||
let invoc = match import.function.ret {
|
||||
Some(shared::TYPE_NUMBER) => format!("return {};", invoc),
|
||||
Some(shared::TYPE_BOOLEAN) => format!("return {} ? 1 : 0;", invoc),
|
||||
|
@ -528,6 +528,16 @@ impl Import {
|
||||
}
|
||||
ImportKind::Normal => {}
|
||||
}
|
||||
|
||||
let mut getter = None;
|
||||
let mut setter = None;
|
||||
|
||||
if self.function.opts.getter() {
|
||||
getter = Some(self.infer_getter_property());
|
||||
}
|
||||
if self.function.opts.setter() {
|
||||
setter = Some(self.infer_setter_property());
|
||||
}
|
||||
a.fields(&[
|
||||
("module", &|a| {
|
||||
match self.module {
|
||||
@ -539,6 +549,18 @@ impl Import {
|
||||
("method", &|a| a.bool(method)),
|
||||
("js_new", &|a| a.bool(js_new)),
|
||||
("statik", &|a| a.bool(statik)),
|
||||
("getter", &|a| {
|
||||
match getter {
|
||||
Some(ref s) => a.str(s),
|
||||
None => a.append("null"),
|
||||
}
|
||||
}),
|
||||
("setter", &|a| {
|
||||
match setter {
|
||||
Some(ref s) => a.str(s),
|
||||
None => a.append("null"),
|
||||
}
|
||||
}),
|
||||
("function", &|a| self.function.wbg_literal(a)),
|
||||
("class", &|a| {
|
||||
match class_name {
|
||||
@ -548,6 +570,16 @@ impl Import {
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
fn infer_getter_property(&self) -> String {
|
||||
self.function.name.as_ref().to_string()
|
||||
}
|
||||
|
||||
fn infer_setter_property(&self) -> String {
|
||||
let name = self.function.name.as_ref();
|
||||
assert!(name.starts_with("set_"), "setters must start with `set_`");
|
||||
name[4..].to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Struct {
|
||||
@ -702,6 +734,26 @@ impl BindgenAttrs {
|
||||
})
|
||||
.next()
|
||||
}
|
||||
|
||||
fn getter(&self) -> bool {
|
||||
self.attrs.iter()
|
||||
.any(|a| {
|
||||
match *a {
|
||||
BindgenAttr::Getter => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn setter(&self) -> bool {
|
||||
self.attrs.iter()
|
||||
.any(|a| {
|
||||
match *a {
|
||||
BindgenAttr::Setter => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl syn::synom::Synom for BindgenAttrs {
|
||||
@ -725,6 +777,8 @@ enum BindgenAttr {
|
||||
Method,
|
||||
Static(syn::Type),
|
||||
Module(String),
|
||||
Getter,
|
||||
Setter,
|
||||
}
|
||||
|
||||
impl syn::synom::Synom for BindgenAttr {
|
||||
@ -735,6 +789,10 @@ impl syn::synom::Synom for BindgenAttr {
|
||||
|
|
||||
call!(term, "method") => { |_| BindgenAttr::Method }
|
||||
|
|
||||
call!(term, "getter") => { |_| BindgenAttr::Getter }
|
||||
|
|
||||
call!(term, "setter") => { |_| BindgenAttr::Setter }
|
||||
|
|
||||
do_parse!(
|
||||
call!(term, "static") >>
|
||||
punct!(=) >>
|
||||
|
@ -19,6 +19,8 @@ pub struct Import {
|
||||
pub method: bool,
|
||||
pub js_new: bool,
|
||||
pub statik: bool,
|
||||
pub getter: Option<String>,
|
||||
pub setter: Option<String>,
|
||||
pub class: Option<String>,
|
||||
pub function: Function,
|
||||
}
|
||||
|
@ -278,3 +278,60 @@ fn switch_methods() {
|
||||
"#)
|
||||
.test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn properties() {
|
||||
test_support::project()
|
||||
.file("src/lib.rs", r#"
|
||||
#![feature(proc_macro)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(module = "./test")]
|
||||
extern {
|
||||
type Foo;
|
||||
|
||||
#[wasm_bindgen(constructor)]
|
||||
fn new() -> Foo;
|
||||
|
||||
#[wasm_bindgen(getter, method)]
|
||||
fn a(this: &Foo) -> i32;
|
||||
|
||||
#[wasm_bindgen(setter, method)]
|
||||
fn set_a(this: &Foo, a: i32);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[no_mangle]
|
||||
pub extern fn run() {
|
||||
let a = Foo::new();
|
||||
assert_eq!(a.a(), 1);
|
||||
a.set_a(2);
|
||||
assert_eq!(a.a(), 2);
|
||||
}
|
||||
"#)
|
||||
.file("test.ts", r#"
|
||||
import { run } from "./out";
|
||||
|
||||
export class Foo {
|
||||
constructor(private num: number) {
|
||||
this.num = 1;
|
||||
}
|
||||
|
||||
get a() {
|
||||
return this.num;
|
||||
}
|
||||
|
||||
set a(val) {
|
||||
this.num = val;
|
||||
}
|
||||
}
|
||||
|
||||
export function test() {
|
||||
run();
|
||||
}
|
||||
"#)
|
||||
.test();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user