mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-12 07:06:07 +00:00
wip
This commit is contained in:
parent
ec1c263480
commit
8f8da49dab
@ -109,6 +109,7 @@ fn extract_program(module: &mut Module) -> shared::Program {
|
|||||||
structs: Vec::new(),
|
structs: Vec::new(),
|
||||||
free_functions: Vec::new(),
|
free_functions: Vec::new(),
|
||||||
imports: Vec::new(),
|
imports: Vec::new(),
|
||||||
|
imported_structs: Vec::new(),
|
||||||
};
|
};
|
||||||
let data = match data {
|
let data = match data {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
@ -126,10 +127,11 @@ fn extract_program(module: &mut Module) -> shared::Program {
|
|||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
};
|
};
|
||||||
let shared::Program { structs, free_functions, imports } = p;
|
let shared::Program { structs, free_functions, imports, imported_structs } = p;
|
||||||
ret.structs.extend(structs);
|
ret.structs.extend(structs);
|
||||||
ret.free_functions.extend(free_functions);
|
ret.free_functions.extend(free_functions);
|
||||||
ret.imports.extend(imports);
|
ret.imports.extend(imports);
|
||||||
|
ret.imported_structs.extend(imported_structs);
|
||||||
}
|
}
|
||||||
data.entries_mut().remove(i);
|
data.entries_mut().remove(i);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ pub struct Program {
|
|||||||
pub structs: Vec<Struct>,
|
pub structs: Vec<Struct>,
|
||||||
pub free_functions: Vec<Function>,
|
pub free_functions: Vec<Function>,
|
||||||
pub imports: Vec<Import>,
|
pub imports: Vec<Import>,
|
||||||
|
pub imported_structs: Vec<ImportStruct>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
@ -16,11 +17,21 @@ pub struct Function {
|
|||||||
|
|
||||||
pub struct Import {
|
pub struct Import {
|
||||||
pub module: String,
|
pub module: String,
|
||||||
pub function: Function,
|
pub function: ImportFunction,
|
||||||
pub decl: Box<syn::FnDecl>,
|
}
|
||||||
|
|
||||||
|
pub struct ImportFunction {
|
||||||
pub ident: syn::Ident,
|
pub ident: syn::Ident,
|
||||||
pub vis: syn::Visibility,
|
pub wasm_function: Function,
|
||||||
pub attrs: Vec<syn::Attribute>,
|
pub rust_decl: Box<syn::FnDecl>,
|
||||||
|
pub rust_vis: syn::Visibility,
|
||||||
|
pub rust_attrs: Vec<syn::Attribute>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ImportStruct {
|
||||||
|
pub module: Option<String>,
|
||||||
|
pub name: syn::Ident,
|
||||||
|
pub functions: Vec<(bool, ImportFunction)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
@ -103,23 +114,51 @@ impl Program {
|
|||||||
})
|
})
|
||||||
.expect("must specify `#[wasm_module = ...]` for module to import from");
|
.expect("must specify `#[wasm_module = ...]` for module to import from");
|
||||||
for item in f.items.iter() {
|
for item in f.items.iter() {
|
||||||
self.push_foreign_item(&module, item);
|
let import = self.gen_foreign_item(item, false).0;
|
||||||
|
self.imports.push(Import {
|
||||||
|
module: module.clone(),
|
||||||
|
function: import,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_foreign_item(&mut self, module: &str, f: &syn::ForeignItem) {
|
pub fn gen_foreign_item(&mut self,
|
||||||
|
f: &syn::ForeignItem,
|
||||||
|
allow_self: bool) -> (ImportFunction, bool) {
|
||||||
let f = match *f {
|
let f = match *f {
|
||||||
syn::ForeignItem::Fn(ref f) => f,
|
syn::ForeignItem::Fn(ref f) => f,
|
||||||
_ => panic!("only foreign functions allowed for now, not statics"),
|
_ => panic!("only foreign functions allowed for now, not statics"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.imports.push(Import {
|
let (wasm, mutable) = Function::from_decl(f.ident, &f.decl, allow_self);
|
||||||
module: module.to_string(),
|
let is_method = match mutable {
|
||||||
attrs: f.attrs.clone(),
|
Some(false) => true,
|
||||||
vis: f.vis.clone(),
|
None => false,
|
||||||
decl: f.decl.clone(),
|
Some(true) => {
|
||||||
|
panic!("mutable self methods not allowed in extern structs");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(ImportFunction {
|
||||||
|
rust_attrs: f.attrs.clone(),
|
||||||
|
rust_vis: f.vis.clone(),
|
||||||
|
rust_decl: f.decl.clone(),
|
||||||
ident: f.ident.clone(),
|
ident: f.ident.clone(),
|
||||||
function: Function::from_decl(f.ident, &f.decl),
|
wasm_function: wasm,
|
||||||
|
}, is_method)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_extern_class(&mut self, class: &ExternClass) {
|
||||||
|
let functions = class.functions.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let (f, method) = self.gen_foreign_item(f, true);
|
||||||
|
(method, f)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
self.imported_structs.push(ImportStruct {
|
||||||
|
module: class.module.as_ref().map(|s| s.value()),
|
||||||
|
name: class.name,
|
||||||
|
functions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +167,10 @@ impl Program {
|
|||||||
structs: self.structs.iter().map(|s| s.shared()).collect(),
|
structs: self.structs.iter().map(|s| s.shared()).collect(),
|
||||||
free_functions: self.free_functions.iter().map(|s| s.shared()).collect(),
|
free_functions: self.free_functions.iter().map(|s| s.shared()).collect(),
|
||||||
imports: self.imports.iter()
|
imports: self.imports.iter()
|
||||||
.map(|i| (i.module.clone(), i.function.shared()))
|
.map(|i| (i.module.clone(), i.function.wasm_function.shared()))
|
||||||
|
.collect(),
|
||||||
|
imported_structs: self.imported_structs.iter()
|
||||||
|
.map(|i| i.shared())
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,10 +195,12 @@ impl Function {
|
|||||||
panic!("can only bindgen Rust ABI functions")
|
panic!("can only bindgen Rust ABI functions")
|
||||||
}
|
}
|
||||||
|
|
||||||
Function::from_decl(input.ident, &input.decl)
|
Function::from_decl(input.ident, &input.decl, false).0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_decl(name: syn::Ident, decl: &syn::FnDecl) -> Function {
|
pub fn from_decl(name: syn::Ident,
|
||||||
|
decl: &syn::FnDecl,
|
||||||
|
allow_self: bool) -> (Function, Option<bool>) {
|
||||||
if decl.variadic.is_some() {
|
if decl.variadic.is_some() {
|
||||||
panic!("can't bindgen variadic functions")
|
panic!("can't bindgen variadic functions")
|
||||||
}
|
}
|
||||||
@ -164,10 +208,19 @@ impl Function {
|
|||||||
panic!("can't bindgen functions with lifetime or type parameters")
|
panic!("can't bindgen functions with lifetime or type parameters")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut mutable = None;
|
||||||
let arguments = decl.inputs.iter()
|
let arguments = decl.inputs.iter()
|
||||||
.map(|arg| {
|
.filter_map(|arg| {
|
||||||
match *arg {
|
match *arg {
|
||||||
syn::FnArg::Captured(ref c) => c,
|
syn::FnArg::Captured(ref c) => Some(c),
|
||||||
|
syn::FnArg::SelfValue(_) => {
|
||||||
|
panic!("by-value `self` not yet supported");
|
||||||
|
}
|
||||||
|
syn::FnArg::SelfRef(ref a) if allow_self => {
|
||||||
|
assert!(mutable.is_none());
|
||||||
|
mutable = Some(a.mutability.is_some());
|
||||||
|
None
|
||||||
|
}
|
||||||
_ => panic!("arguments cannot be `self` or ignored"),
|
_ => panic!("arguments cannot be `self` or ignored"),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -179,7 +232,7 @@ impl Function {
|
|||||||
syn::ReturnType::Type(_, ref t) => Some(Type::from(t)),
|
syn::ReturnType::Type(_, ref t) => Some(Type::from(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
Function { name, arguments, ret }
|
(Function { name, arguments, ret }, mutable)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_function_export_name(&self) -> syn::LitStr {
|
pub fn free_function_export_name(&self) -> syn::LitStr {
|
||||||
@ -346,38 +399,9 @@ impl Struct {
|
|||||||
panic!("can only bindgen safe functions");
|
panic!("can only bindgen safe functions");
|
||||||
}
|
}
|
||||||
|
|
||||||
if method.sig.decl.variadic.is_some() {
|
let (function, mutable) = Function::from_decl(method.sig.ident,
|
||||||
panic!("can't bindgen variadic functions")
|
&method.sig.decl,
|
||||||
}
|
true);
|
||||||
if method.sig.decl.generics.params.len() > 0 {
|
|
||||||
panic!("can't bindgen functions with lifetime or type parameters")
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut mutable = None;
|
|
||||||
let arguments = method.sig.decl.inputs.iter()
|
|
||||||
.filter_map(|arg| {
|
|
||||||
match *arg {
|
|
||||||
syn::FnArg::Captured(ref c) => Some(c),
|
|
||||||
syn::FnArg::SelfValue(_) => {
|
|
||||||
panic!("by-value `self` not yet supported");
|
|
||||||
}
|
|
||||||
syn::FnArg::SelfRef(ref a) => {
|
|
||||||
assert!(mutable.is_none());
|
|
||||||
mutable = Some(a.mutability.is_some());
|
|
||||||
None
|
|
||||||
}
|
|
||||||
_ => panic!("arguments cannot be `self` or ignored"),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|arg| Type::from(&arg.ty))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let ret = match method.sig.decl.output {
|
|
||||||
syn::ReturnType::Default => None,
|
|
||||||
syn::ReturnType::Type(_, ref t) => Some(Type::from(t)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let function = Function { name: method.sig.ident, arguments, ret };
|
|
||||||
match mutable {
|
match mutable {
|
||||||
Some(mutable) => {
|
Some(mutable) => {
|
||||||
self.methods.push(Method { mutable, function });
|
self.methods.push(Method { mutable, function });
|
||||||
@ -405,3 +429,77 @@ impl Method {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ImportStruct {
|
||||||
|
fn shared(&self) -> shared::ImportStruct {
|
||||||
|
shared::ImportStruct {
|
||||||
|
module: self.module.clone(),
|
||||||
|
name: self.name.to_string(),
|
||||||
|
functions: self.functions.iter()
|
||||||
|
.map(|&(b, ref f)| (b, f.wasm_function.shared()))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct File {
|
||||||
|
pub items: Vec<MyItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl syn::synom::Synom for File {
|
||||||
|
named!(parse -> Self, map!(many0!(syn!(MyItem)), |items| File { items }));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MyItem {
|
||||||
|
Normal(syn::Item),
|
||||||
|
ExternClass(ExternClass),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl syn::synom::Synom for MyItem {
|
||||||
|
named!(parse -> Self, alt!(
|
||||||
|
syn!(syn::Item) => { MyItem::Normal }
|
||||||
|
|
|
||||||
|
syn!(ExternClass) => { MyItem::ExternClass }
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ExternClass {
|
||||||
|
name: syn::Ident,
|
||||||
|
module: Option<syn::LitStr>,
|
||||||
|
functions: Vec<syn::ForeignItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl syn::synom::Synom for ExternClass {
|
||||||
|
named!(parse -> Self, do_parse!(
|
||||||
|
module: option!(do_parse!(
|
||||||
|
punct!(#) >>
|
||||||
|
name: brackets!(do_parse!(
|
||||||
|
call!(term, "wasm_module") >>
|
||||||
|
punct!(=) >>
|
||||||
|
val: syn!(syn::LitStr) >>
|
||||||
|
(val)
|
||||||
|
)) >>
|
||||||
|
(name.1)
|
||||||
|
)) >>
|
||||||
|
keyword!(extern) >>
|
||||||
|
keyword!(struct) >>
|
||||||
|
name: syn!(syn::Ident) >>
|
||||||
|
items: braces!(many0!(syn!(syn::ForeignItem))) >>
|
||||||
|
(ExternClass {
|
||||||
|
name,
|
||||||
|
module,
|
||||||
|
functions: items.1,
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term<'a>(cursor: syn::buffer::Cursor<'a>, name: &str)
|
||||||
|
-> syn::synom::PResult<'a, ()>
|
||||||
|
{
|
||||||
|
if let Some((_span, term, next)) = cursor.term() {
|
||||||
|
if term.as_str() == name {
|
||||||
|
return Ok(((), next))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syn::parse_error()
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![feature(proc_macro)]
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate quote;
|
extern crate quote;
|
||||||
@ -26,7 +27,7 @@ macro_rules! my_quote {
|
|||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
||||||
// Parse the input as a list of Rust items, reusing the `syn::File` parser.
|
// Parse the input as a list of Rust items, reusing the `syn::File` parser.
|
||||||
let file = syn::parse::<syn::File>(input)
|
let file = syn::parse::<ast::File>(input)
|
||||||
.expect("expected a set of valid Rust items");
|
.expect("expected a set of valid Rust items");
|
||||||
|
|
||||||
let mut ret = Tokens::new();
|
let mut ret = Tokens::new();
|
||||||
@ -35,12 +36,21 @@ pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
|||||||
structs: Vec::new(),
|
structs: Vec::new(),
|
||||||
free_functions: Vec::new(),
|
free_functions: Vec::new(),
|
||||||
imports: Vec::new(),
|
imports: Vec::new(),
|
||||||
|
imported_structs: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Translate all input items into our own internal representation (the `ast`
|
// Translate all input items into our own internal representation (the `ast`
|
||||||
// module). We'll be panicking here on anything that we can't process
|
// module). We'll be panicking here on anything that we can't process
|
||||||
|
|
||||||
for item in file.items.iter() {
|
for item in file.items.iter() {
|
||||||
|
let item = match *item {
|
||||||
|
ast::MyItem::ExternClass(ref c) => {
|
||||||
|
program.push_extern_class(c);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ast::MyItem::Normal(ref item) => item,
|
||||||
|
};
|
||||||
|
|
||||||
match *item {
|
match *item {
|
||||||
syn::Item::Fn(ref f) => {
|
syn::Item::Fn(ref f) => {
|
||||||
item.to_tokens(&mut ret);
|
item.to_tokens(&mut ret);
|
||||||
@ -76,6 +86,9 @@ pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
|||||||
for i in program.imports.iter() {
|
for i in program.imports.iter() {
|
||||||
bindgen_import(i, &mut ret);
|
bindgen_import(i, &mut ret);
|
||||||
}
|
}
|
||||||
|
for i in program.imported_structs.iter() {
|
||||||
|
bindgen_imported_struct(i, &mut ret);
|
||||||
|
}
|
||||||
|
|
||||||
// Finally generate a static which will eventually be what lives in a custom
|
// Finally generate a static which will eventually be what lives in a custom
|
||||||
// section of the wasm executable. For now it's just a plain old static, but
|
// section of the wasm executable. For now it's just a plain old static, but
|
||||||
@ -416,18 +429,53 @@ impl ToTokens for Receiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
|
fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
|
||||||
let vis = &import.vis;
|
bindgen_import_function(&import.function,
|
||||||
let ret = &import.decl.output;
|
&import.function.ident.to_string(),
|
||||||
let name = &import.ident;
|
Some(&import.module),
|
||||||
let fn_token = &import.decl.fn_token;
|
tokens);
|
||||||
let arguments = &import.decl.inputs;
|
}
|
||||||
|
|
||||||
|
fn bindgen_imported_struct(import: &ast::ImportStruct, tokens: &mut Tokens) {
|
||||||
|
let name = import.name;
|
||||||
|
(my_quote! {
|
||||||
|
pub struct #name {
|
||||||
|
obj: ::wasm_bindgen::JsObject,
|
||||||
|
}
|
||||||
|
}).to_tokens(tokens);
|
||||||
|
|
||||||
|
let mut methods = Tokens::new();
|
||||||
|
|
||||||
|
for &(_is_method, ref f) in import.functions.iter() {
|
||||||
|
let import_name = format!("__wbg_{}_{}", name, f.ident);
|
||||||
|
|
||||||
|
bindgen_import_function(f,
|
||||||
|
&import_name,
|
||||||
|
import.module.as_ref().map(|s| &**s),
|
||||||
|
&mut methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
(my_quote! {
|
||||||
|
impl #name {
|
||||||
|
#methods
|
||||||
|
}
|
||||||
|
}).to_tokens(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bindgen_import_function(import: &ast::ImportFunction,
|
||||||
|
import_name: &str,
|
||||||
|
_import_module: Option<&str>,
|
||||||
|
tokens: &mut Tokens) {
|
||||||
|
let vis = &import.rust_vis;
|
||||||
|
let ret = &import.rust_decl.output;
|
||||||
|
let fn_token = &import.rust_decl.fn_token;
|
||||||
|
let arguments = &import.rust_decl.inputs;
|
||||||
|
|
||||||
let mut abi_argument_names = Vec::new();
|
let mut abi_argument_names = Vec::new();
|
||||||
let mut abi_arguments = Vec::new();
|
let mut abi_arguments = Vec::new();
|
||||||
let mut arg_conversions = Vec::new();
|
let mut arg_conversions = Vec::new();
|
||||||
let ret_ident = syn::Ident::from("_ret");
|
let ret_ident = syn::Ident::from("_ret");
|
||||||
|
|
||||||
let names = import.decl.inputs
|
let names = import.rust_decl.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| {
|
.map(|arg| {
|
||||||
match *arg {
|
match *arg {
|
||||||
@ -449,7 +497,7 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (ty, name) in import.function.arguments.iter().zip(names) {
|
for (ty, name) in import.wasm_function.arguments.iter().zip(names) {
|
||||||
match *ty {
|
match *ty {
|
||||||
ast::Type::Integer(i) => {
|
ast::Type::Integer(i) => {
|
||||||
abi_argument_names.push(name);
|
abi_argument_names.push(name);
|
||||||
@ -507,7 +555,7 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
|
|||||||
}
|
}
|
||||||
let abi_ret;
|
let abi_ret;
|
||||||
let convert_ret;
|
let convert_ret;
|
||||||
match import.function.ret {
|
match import.wasm_function.ret {
|
||||||
Some(ast::Type::Integer(i)) => {
|
Some(ast::Type::Integer(i)) => {
|
||||||
abi_ret = my_quote! { #i };
|
abi_ret = my_quote! { #i };
|
||||||
convert_ret = my_quote! { #ret_ident };
|
convert_ret = my_quote! { #ret_ident };
|
||||||
@ -542,14 +590,16 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let name = import.ident;
|
||||||
|
let import_name = syn::Ident::from(import_name);
|
||||||
(quote! {
|
(quote! {
|
||||||
#vis #fn_token #name(#arguments) #ret {
|
#vis #fn_token #name(#arguments) #ret {
|
||||||
extern {
|
extern {
|
||||||
fn #name(#(#abi_arguments),*) -> #abi_ret;
|
fn #import_name(#(#abi_arguments),*) -> #abi_ret;
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
#(#arg_conversions)*
|
#(#arg_conversions)*
|
||||||
let #ret_ident = #name(#(#abi_argument_names),*);
|
let #ret_ident = #import_name(#(#abi_argument_names),*);
|
||||||
#convert_ret
|
#convert_ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ pub struct Program {
|
|||||||
pub structs: Vec<Struct>,
|
pub structs: Vec<Struct>,
|
||||||
pub free_functions: Vec<Function>,
|
pub free_functions: Vec<Function>,
|
||||||
pub imports: Vec<(String, Function)>,
|
pub imports: Vec<(String, Function)>,
|
||||||
|
pub imported_structs: Vec<ImportStruct>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@ -15,6 +16,13 @@ pub struct Struct {
|
|||||||
pub methods: Vec<Method>,
|
pub methods: Vec<Method>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct ImportStruct {
|
||||||
|
pub module: Option<String>,
|
||||||
|
pub name: String,
|
||||||
|
pub functions: Vec<(bool, Function)>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Method {
|
pub struct Method {
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
|
31
tests/import-class.rs
Normal file
31
tests/import-class.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
extern crate test_support;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple() {
|
||||||
|
test_support::project()
|
||||||
|
.file("src/lib.rs", r#"
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
wasm_bindgen! {
|
||||||
|
extern struct Math {
|
||||||
|
fn random() -> f64;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_random() -> f64 {
|
||||||
|
Math::random()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.file("test.ts", r#"
|
||||||
|
import * as wasm from "./out";
|
||||||
|
|
||||||
|
export function test() {
|
||||||
|
wasm.get_random();
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.test();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user