mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-14 16:36:07 +00:00
Add a structural
bindgen attribute
This attribute indicates that methods are to be accessed in a structural method rather than through their class. This should allow direct access to properties embedded on objects rather than forcing all objects to have a class/prototype.
This commit is contained in:
parent
0e1fee5ddd
commit
8830f540a9
@ -1,5 +1,6 @@
|
|||||||
use std::char;
|
use std::char;
|
||||||
use std::collections::{HashSet, HashMap};
|
use std::collections::{HashSet, HashMap};
|
||||||
|
use std::fmt::Write;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use shared;
|
use shared;
|
||||||
@ -1432,6 +1433,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let nargs = invoc_args.len();
|
||||||
let invoc_args = invoc_args.join(", ");
|
let invoc_args = invoc_args.join(", ");
|
||||||
let function_name = &import.function.name;
|
let function_name = &import.function.name;
|
||||||
let invoc = match import.class {
|
let invoc = match import.class {
|
||||||
@ -1441,19 +1443,50 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
Some(ref class) if import.method => {
|
Some(ref class) if import.method => {
|
||||||
let class = self.import_name(info, class);
|
let class = self.import_name(info, class);
|
||||||
let target = if let Some(ref g) = import.getter {
|
let target = if let Some(ref g) = import.getter {
|
||||||
format!(
|
if import.structural {
|
||||||
"Object.getOwnPropertyDescriptor({}.prototype, '{}').get;",
|
format!("function() {{ return this.{}; }}", g)
|
||||||
class,
|
} else {
|
||||||
g,
|
format!(
|
||||||
)
|
"Object.getOwnPropertyDescriptor\
|
||||||
|
({}.prototype, '{}').get;",
|
||||||
|
class,
|
||||||
|
g,
|
||||||
|
)
|
||||||
|
}
|
||||||
} else if let Some(ref s) = import.setter {
|
} else if let Some(ref s) = import.setter {
|
||||||
format!(
|
if import.structural {
|
||||||
"Object.getOwnPropertyDescriptor({}.prototype, '{}').set;",
|
format!("function(y) {{ this.{} = y; }}", s)
|
||||||
class,
|
} else {
|
||||||
s,
|
format!(
|
||||||
)
|
"Object.getOwnPropertyDescriptor\
|
||||||
|
({}.prototype, '{}').set;",
|
||||||
|
class,
|
||||||
|
s,
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
format!("{}.prototype.{}", class, function_name)
|
if import.structural {
|
||||||
|
let mut s = format!("function(");
|
||||||
|
for i in 0..nargs - 1 {
|
||||||
|
if i > 0 {
|
||||||
|
drop(write!(s, ", "));
|
||||||
|
}
|
||||||
|
drop(write!(s, "x{}", i));
|
||||||
|
}
|
||||||
|
s.push_str(") { return this.");
|
||||||
|
s.push_str(function_name);
|
||||||
|
s.push_str("(");
|
||||||
|
for i in 0..nargs - 1 {
|
||||||
|
if i > 0 {
|
||||||
|
drop(write!(s, ", "));
|
||||||
|
}
|
||||||
|
drop(write!(s, "x{}", i));
|
||||||
|
}
|
||||||
|
s.push_str("); }");
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
format!("{}.prototype.{}", class, function_name)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.cx.globals.push_str(&format!("
|
self.cx.globals.push_str(&format!("
|
||||||
const {}_target = {};
|
const {}_target = {};
|
||||||
|
@ -670,6 +670,16 @@ impl BindgenAttrs {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn structural(&self) -> bool {
|
||||||
|
self.attrs.iter()
|
||||||
|
.any(|a| {
|
||||||
|
match *a {
|
||||||
|
BindgenAttr::Structural => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl syn::synom::Synom for BindgenAttrs {
|
impl syn::synom::Synom for BindgenAttrs {
|
||||||
@ -695,6 +705,7 @@ enum BindgenAttr {
|
|||||||
Module(String),
|
Module(String),
|
||||||
Getter,
|
Getter,
|
||||||
Setter,
|
Setter,
|
||||||
|
Structural,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl syn::synom::Synom for BindgenAttr {
|
impl syn::synom::Synom for BindgenAttr {
|
||||||
@ -709,6 +720,8 @@ impl syn::synom::Synom for BindgenAttr {
|
|||||||
|
|
|
|
||||||
call!(term, "setter") => { |_| BindgenAttr::Setter }
|
call!(term, "setter") => { |_| BindgenAttr::Setter }
|
||||||
|
|
|
|
||||||
|
call!(term, "structural") => { |_| BindgenAttr::Structural }
|
||||||
|
|
|
||||||
do_parse!(
|
do_parse!(
|
||||||
call!(term, "js_namespace") >>
|
call!(term, "js_namespace") >>
|
||||||
punct!(=) >>
|
punct!(=) >>
|
||||||
|
@ -349,6 +349,16 @@ impl ToTokens for ast::ImportType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ::wasm_bindgen::convert::FromRefWasmBoundary for #name {
|
||||||
|
type RefAnchor = ::std::mem::ManuallyDrop<#name>;
|
||||||
|
unsafe fn from_js_ref(js: Self::Js) -> Self::RefAnchor {
|
||||||
|
let obj = <::wasm_bindgen::JsValue as ::wasm_bindgen::convert::WasmBoundary>
|
||||||
|
::from_js(js);
|
||||||
|
::std::mem::ManuallyDrop::new(#name { obj })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl From<::wasm_bindgen::JsValue> for #name {
|
impl From<::wasm_bindgen::JsValue> for #name {
|
||||||
fn from(obj: ::wasm_bindgen::JsValue) -> #name {
|
fn from(obj: ::wasm_bindgen::JsValue) -> #name {
|
||||||
#name { obj }
|
#name { obj }
|
||||||
|
@ -242,6 +242,7 @@ impl Literal for ast::ImportFunction {
|
|||||||
|
|
||||||
let mut getter = None;
|
let mut getter = None;
|
||||||
let mut setter = None;
|
let mut setter = None;
|
||||||
|
let structural = self.function.opts.structural();
|
||||||
|
|
||||||
if self.function.opts.getter() {
|
if self.function.opts.getter() {
|
||||||
getter = Some(self.infer_getter_property());
|
getter = Some(self.infer_getter_property());
|
||||||
@ -254,6 +255,7 @@ impl Literal for ast::ImportFunction {
|
|||||||
("catch", &|a| a.bool(self.function.opts.catch())),
|
("catch", &|a| a.bool(self.function.opts.catch())),
|
||||||
("method", &|a| a.bool(method)),
|
("method", &|a| a.bool(method)),
|
||||||
("js_new", &|a| a.bool(js_new)),
|
("js_new", &|a| a.bool(js_new)),
|
||||||
|
("structural", &|a| a.bool(structural)),
|
||||||
("getter", &|a| match getter {
|
("getter", &|a| match getter {
|
||||||
Some(ref s) => a.str(s),
|
Some(ref s) => a.str(s),
|
||||||
None => a.append("null"),
|
None => a.append("null"),
|
||||||
|
@ -38,6 +38,7 @@ pub struct ImportFunction {
|
|||||||
pub catch: bool,
|
pub catch: bool,
|
||||||
pub method: bool,
|
pub method: bool,
|
||||||
pub js_new: bool,
|
pub js_new: bool,
|
||||||
|
pub structural: bool,
|
||||||
pub getter: Option<String>,
|
pub getter: Option<String>,
|
||||||
pub setter: Option<String>,
|
pub setter: Option<String>,
|
||||||
pub class: Option<String>,
|
pub class: Option<String>,
|
||||||
|
50
tests/structural.rs
Normal file
50
tests/structural.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
extern crate test_support;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn works() {
|
||||||
|
test_support::project()
|
||||||
|
.detect_node(true)
|
||||||
|
.file("src/lib.rs", r#"
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern {
|
||||||
|
pub type Foo;
|
||||||
|
|
||||||
|
#[wasm_bindgen(method, structural)]
|
||||||
|
fn bar(this: &Foo);
|
||||||
|
#[wasm_bindgen(method, getter, structural)]
|
||||||
|
fn baz(this: &Foo) -> u32;
|
||||||
|
#[wasm_bindgen(method, setter, structural)]
|
||||||
|
fn set_baz(this: &Foo, val: u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn run(a: &Foo) {
|
||||||
|
a.bar();
|
||||||
|
assert_eq!(a.baz(), 1);
|
||||||
|
a.set_baz(2);
|
||||||
|
assert_eq!(a.baz(), 2);
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.file("test.ts", r#"
|
||||||
|
import * as assert from "assert";
|
||||||
|
import { run } from "./out";
|
||||||
|
|
||||||
|
export function test() {
|
||||||
|
let called = false;
|
||||||
|
run({
|
||||||
|
bar() { called = true; },
|
||||||
|
baz: 1,
|
||||||
|
});
|
||||||
|
assert.strictEqual(called, true);
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.test();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user