Implement a js_name customization

This'll allow binding multiple signatures of a JS function as well as otherwise
changing the name of the JS function you're calling from the Rust function that
you're defining.

Closes #72
This commit is contained in:
Alex Crichton
2018-03-22 19:05:14 -07:00
parent a8045fbbe9
commit 7ebc428646
10 changed files with 155 additions and 66 deletions

View File

@ -33,7 +33,9 @@ pub enum ImportKind {
pub struct ImportFunction {
pub function: Function,
pub rust_name: syn::Ident,
pub kind: ImportFunctionKind,
pub shim: syn::Ident,
}
pub enum ImportFunctionKind {
@ -51,7 +53,9 @@ pub enum ImportFunctionKind {
pub struct ImportStatic {
pub vis: syn::Visibility,
pub ty: syn::Type,
pub name: syn::Ident,
pub shim: syn::Ident,
pub rust_name: syn::Ident,
pub js_name: syn::Ident,
}
pub struct ImportType {
@ -273,7 +277,7 @@ impl Program {
let mut kind = match item {
syn::ForeignItem::Fn(f) => self.push_foreign_fn(f, item_opts),
syn::ForeignItem::Type(t) => self.push_foreign_ty(t),
syn::ForeignItem::Static(s) => self.push_foreign_static(s),
syn::ForeignItem::Static(s) => self.push_foreign_static(s, item_opts),
_ => panic!("only foreign functions/types allowed for now"),
};
@ -284,7 +288,8 @@ impl Program {
pub fn push_foreign_fn(&mut self, f: syn::ForeignItemFn, opts: BindgenAttrs)
-> ImportKind
{
let mut wasm = Function::from_decl(f.ident,
let js_name = opts.js_name().unwrap_or(f.ident);
let mut wasm = Function::from_decl(js_name,
f.decl,
f.attrs,
opts,
@ -346,9 +351,19 @@ impl Program {
ImportFunctionKind::Normal
};
let shim = {
let ns = match kind {
ImportFunctionKind::Normal => "n",
ImportFunctionKind::Method { ref class, .. } => class,
ImportFunctionKind::JsConstructor { ref class, .. } => class,
};
format!("__wbg_f_{}_{}_{}", js_name, f.ident, ns)
};
ImportKind::Function(ImportFunction {
function: wasm,
kind,
rust_name: f.ident,
shim: shim.into(),
})
}
@ -361,16 +376,22 @@ impl Program {
})
}
pub fn push_foreign_static(&mut self, f: syn::ForeignItemStatic)
pub fn push_foreign_static(&mut self,
f: syn::ForeignItemStatic,
opts: BindgenAttrs)
-> ImportKind
{
if f.mutability.is_some() {
panic!("cannot import mutable globals yet")
}
let js_name = opts.js_name().unwrap_or(f.ident);
let shim = format!("__wbg_static_accessor_{}_{}", js_name, f.ident);
ImportKind::Static(ImportStatic {
ty: *f.ty,
vis: f.vis,
name: f.ident,
rust_name: f.ident,
js_name,
shim: shim.into(),
})
}
@ -651,22 +672,22 @@ impl BindgenAttrs {
.next()
}
pub fn getter(&self) -> Option<Option<String>> {
pub fn getter(&self) -> Option<Option<syn::Ident>> {
self.attrs.iter()
.filter_map(|a| {
match *a {
BindgenAttr::Getter(ref s) => Some(s.clone()),
BindgenAttr::Getter(s) => Some(s),
_ => None,
}
})
.next()
}
pub fn setter(&self) -> Option<Option<String>> {
pub fn setter(&self) -> Option<Option<syn::Ident>> {
self.attrs.iter()
.filter_map(|a| {
match *a {
BindgenAttr::Setter(ref s) => Some(s.clone()),
BindgenAttr::Setter(s) => Some(s),
_ => None,
}
})
@ -682,6 +703,17 @@ impl BindgenAttrs {
}
})
}
pub fn js_name(&self) -> Option<syn::Ident> {
self.attrs.iter()
.filter_map(|a| {
match *a {
BindgenAttr::JsName(s) => Some(s),
_ => None,
}
})
.next()
}
}
impl syn::synom::Synom for BindgenAttrs {
@ -705,9 +737,10 @@ enum BindgenAttr {
Method,
JsNamespace(syn::Ident),
Module(String),
Getter(Option<String>),
Setter(Option<String>),
Getter(Option<syn::Ident>),
Setter(Option<syn::Ident>),
Structural,
JsName(syn::Ident),
}
impl syn::synom::Synom for BindgenAttr {
@ -722,8 +755,8 @@ impl syn::synom::Synom for BindgenAttr {
call!(term, "getter") >>
val: option!(do_parse!(
punct!(=) >>
s: syn!(syn::LitStr) >>
(s.value())
s: syn!(syn::Ident) >>
(s)
)) >>
(val)
)=> { BindgenAttr::Getter }
@ -732,8 +765,8 @@ impl syn::synom::Synom for BindgenAttr {
call!(term, "setter") >>
val: option!(do_parse!(
punct!(=) >>
s: syn!(syn::LitStr) >>
(s.value())
s: syn!(syn::Ident) >>
(s)
)) >>
(val)
)=> { BindgenAttr::Setter }
@ -753,6 +786,13 @@ impl syn::synom::Synom for BindgenAttr {
s: syn!(syn::LitStr) >>
(s.value())
)=> { BindgenAttr::Module }
|
do_parse!(
call!(term, "js_name") >>
punct!(=) >>
ns: syn!(syn::Ident) >>
(ns)
)=> { BindgenAttr::JsName }
));
}

View File

@ -388,23 +388,16 @@ impl ToTokens for ast::ImportFunction {
fn to_tokens(&self, tokens: &mut Tokens) {
let mut class_ty = None;
let mut is_method = false;
let mut class_name = None;
match self.kind {
ast::ImportFunctionKind::Method { ref ty, ref class } => {
ast::ImportFunctionKind::Method { ref ty, .. } => {
is_method = true;
class_ty = Some(ty);
class_name = Some(class);
}
ast::ImportFunctionKind::JsConstructor { ref ty, ref class } => {
ast::ImportFunctionKind::JsConstructor { ref ty, .. } => {
class_ty = Some(ty);
class_name = Some(class);
}
ast::ImportFunctionKind::Normal => {}
}
let import_name = shared::mangled_import_name(
class_name.map(|s| &**s),
self.function.name.as_ref(),
);
let vis = &self.function.rust_vis;
let ret = &self.function.rust_decl.output;
let fn_token = &self.function.rust_decl.fn_token;
@ -552,8 +545,8 @@ impl ToTokens for ast::ImportFunction {
};
}
let name = self.function.name;
let import_name = syn::Ident::from(import_name);
let rust_name = self.rust_name;
let import_name = self.shim;
let attrs = &self.function.rust_attrs;
let arguments = self.function.rust_decl.inputs
@ -570,7 +563,7 @@ impl ToTokens for ast::ImportFunction {
let invocation = my_quote! {
#(#attrs)*
#[allow(bad_style)]
#vis extern #fn_token #name(#me #(#arguments),*) #ret {
#vis extern #fn_token #rust_name(#me #(#arguments),*) #ret {
::wasm_bindgen::__rt::link_this_library();
extern {
fn #import_name(#(#abi_arguments),*) -> #abi_ret;
@ -637,10 +630,9 @@ impl ToTokens for ast::Enum {
impl ToTokens for ast::ImportStatic {
fn to_tokens(&self, into: &mut Tokens) {
let name = self.name;
let name = self.rust_name;
let ty = &self.ty;
let shim_name = shared::static_import_shim_name(name.as_ref());
let shim_name = syn::Ident::from(shim_name);
let shim_name = self.shim;
let vis = &self.vis;
(my_quote! {
#[allow(bad_style)]

View File

@ -245,9 +245,11 @@ impl Literal for ast::ImportFunction {
let structural = self.function.opts.structural();
if let Some(s) = self.function.opts.getter() {
let s = s.map(|s| s.to_string());
getter = Some(s.unwrap_or_else(|| self.infer_getter_property()));
}
if let Some(s) = self.function.opts.setter() {
let s = s.map(|s| s.to_string());
setter = Some(s.unwrap_or_else(|| self.infer_setter_property()));
}
a.fields(&[
@ -256,6 +258,7 @@ impl Literal for ast::ImportFunction {
("method", &|a| a.bool(method)),
("js_new", &|a| a.bool(js_new)),
("structural", &|a| a.bool(structural)),
("shim", &|a| a.str(self.shim.as_ref())),
("getter", &|a| match getter {
Some(ref s) => a.str(s),
None => a.append("null"),
@ -295,7 +298,8 @@ impl Literal for ast::ImportStatic {
fn literal(&self, a: &mut LiteralBuilder) {
a.fields(&[
("kind", &|a| a.str("static")),
("name", &|a| a.str(self.name.as_ref())),
("name", &|a| a.str(self.js_name.as_ref())),
("shim", &|a| a.str(self.shim.as_ref())),
])
}
}