mirror of
https://github.com/rustwasm/wasm-bindgen.git
synced 2024-12-26 19:45:54 +03:00
Split out the AST and codegen into the wasm-bindgen-backend crate
This commit is contained in:
parent
79ef5979f4
commit
0bd54480c6
10
crates/backend/Cargo.toml
Normal file
10
crates/backend/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = '0.4'
|
||||||
|
proc-macro2 = { version = "0.2", features = ["nightly"] }
|
||||||
|
wasm-bindgen-shared = { path = "../shared", version = "0.1.0" }
|
||||||
|
syn = { version = '0.12', features = ['full'] }
|
@ -1,6 +1,6 @@
|
|||||||
use literal::{self, Literal};
|
use literal::{self, Literal};
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
use quote::{Tokens, ToTokens};
|
use quote::{ToTokens, Tokens};
|
||||||
use shared;
|
use shared;
|
||||||
use syn;
|
use syn;
|
||||||
|
|
||||||
@ -39,14 +39,8 @@ pub struct ImportFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum ImportFunctionKind {
|
pub enum ImportFunctionKind {
|
||||||
Method {
|
Method { class: String, ty: syn::Type },
|
||||||
class: String,
|
JsConstructor { class: String, ty: syn::Type },
|
||||||
ty: syn::Type,
|
|
||||||
},
|
|
||||||
JsConstructor {
|
|
||||||
class: String,
|
|
||||||
ty: syn::Type,
|
|
||||||
},
|
|
||||||
Normal,
|
Normal,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +73,7 @@ pub struct Struct {
|
|||||||
|
|
||||||
pub struct Enum {
|
pub struct Enum {
|
||||||
pub name: syn::Ident,
|
pub name: syn::Ident,
|
||||||
pub variants: Vec<Variant>
|
pub variants: Vec<Variant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Variant {
|
pub struct Variant {
|
||||||
@ -110,20 +104,20 @@ pub enum VectorType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Program {
|
impl Program {
|
||||||
pub fn push_item(&mut self,
|
pub fn push_item(&mut self, item: syn::Item, opts: Option<BindgenAttrs>, tokens: &mut Tokens) {
|
||||||
item: syn::Item,
|
|
||||||
opts: Option<BindgenAttrs>,
|
|
||||||
tokens: &mut Tokens) {
|
|
||||||
match item {
|
match item {
|
||||||
syn::Item::Fn(mut f) => {
|
syn::Item::Fn(mut f) => {
|
||||||
let opts = opts.unwrap_or_else(|| BindgenAttrs::find(&mut f.attrs));
|
let opts = opts.unwrap_or_else(|| BindgenAttrs::find(&mut f.attrs));
|
||||||
|
|
||||||
let no_mangle = f.attrs.iter()
|
let no_mangle = f.attrs
|
||||||
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(i, m)| m.interpret_meta().map(|m| (i, m)))
|
.filter_map(|(i, m)| m.interpret_meta().map(|m| (i, m)))
|
||||||
.find(|&(_, ref m)| m.name() == "no_mangle");
|
.find(|&(_, ref m)| m.name() == "no_mangle");
|
||||||
match no_mangle {
|
match no_mangle {
|
||||||
Some((i, _)) => { f.attrs.remove(i); }
|
Some((i, _)) => {
|
||||||
|
f.attrs.remove(i);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
f.to_tokens(tokens);
|
f.to_tokens(tokens);
|
||||||
@ -153,8 +147,10 @@ impl Program {
|
|||||||
e.to_tokens(tokens);
|
e.to_tokens(tokens);
|
||||||
self.push_enum(e, opts);
|
self.push_enum(e, opts);
|
||||||
}
|
}
|
||||||
_ => panic!("#[wasm_bindgen] can only be applied to a function, \
|
_ => panic!(
|
||||||
struct, enum, impl, or extern block"),
|
"#[wasm_bindgen] can only be applied to a function, \
|
||||||
|
struct, enum, impl, or extern block"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,12 +168,13 @@ impl Program {
|
|||||||
panic!("generic impls aren't supported");
|
panic!("generic impls aren't supported");
|
||||||
}
|
}
|
||||||
let name = match *item.self_ty {
|
let name = match *item.self_ty {
|
||||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
syn::Type::Path(syn::TypePath {
|
||||||
match extract_path_ident(path) {
|
qself: None,
|
||||||
Some(ident) => ident,
|
ref path,
|
||||||
None => panic!("unsupported self type in impl"),
|
}) => match extract_path_ident(path) {
|
||||||
}
|
Some(ident) => ident,
|
||||||
}
|
None => panic!("unsupported self type in impl"),
|
||||||
|
},
|
||||||
_ => panic!("unsupported self type in impl"),
|
_ => panic!("unsupported self type in impl"),
|
||||||
};
|
};
|
||||||
for item in item.items.into_iter() {
|
for item in item.items.into_iter() {
|
||||||
@ -209,12 +206,14 @@ impl Program {
|
|||||||
|
|
||||||
let opts = BindgenAttrs::find(&mut method.attrs);
|
let opts = BindgenAttrs::find(&mut method.attrs);
|
||||||
|
|
||||||
let (function, mutable) = Function::from_decl(method.sig.ident,
|
let (function, mutable) = Function::from_decl(
|
||||||
Box::new(method.sig.decl),
|
method.sig.ident,
|
||||||
method.attrs,
|
Box::new(method.sig.decl),
|
||||||
opts,
|
method.attrs,
|
||||||
method.vis,
|
opts,
|
||||||
true);
|
method.vis,
|
||||||
|
true,
|
||||||
|
);
|
||||||
self.exports.push(Export {
|
self.exports.push(Export {
|
||||||
class: Some(class),
|
class: Some(class),
|
||||||
method: mutable.is_some(),
|
method: mutable.is_some(),
|
||||||
@ -229,30 +228,40 @@ impl Program {
|
|||||||
_ => panic!("only public enums are allowed"),
|
_ => panic!("only public enums are allowed"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let variants = item.variants.iter().enumerate().map(|(i, v)| {
|
let variants = item.variants
|
||||||
match v.fields {
|
.iter()
|
||||||
syn::Fields::Unit => (),
|
.enumerate()
|
||||||
_ => panic!("Only C-Style enums allowed")
|
.map(|(i, v)| {
|
||||||
}
|
match v.fields {
|
||||||
let value = match v.discriminant {
|
syn::Fields::Unit => (),
|
||||||
Some((_, syn::Expr::Lit(syn::ExprLit {attrs: _, lit: syn::Lit::Int(ref int_lit)}))) => {
|
_ => panic!("Only C-Style enums allowed"),
|
||||||
if int_lit.value() > <u32>::max_value() as u64 {
|
}
|
||||||
panic!("Enums can only support numbers that can be represented as u32");
|
let value = match v.discriminant {
|
||||||
|
Some((
|
||||||
|
_,
|
||||||
|
syn::Expr::Lit(syn::ExprLit {
|
||||||
|
attrs: _,
|
||||||
|
lit: syn::Lit::Int(ref int_lit),
|
||||||
|
}),
|
||||||
|
)) => {
|
||||||
|
if int_lit.value() > <u32>::max_value() as u64 {
|
||||||
|
panic!("Enums can only support numbers that can be represented as u32");
|
||||||
|
}
|
||||||
|
int_lit.value() as u32
|
||||||
}
|
}
|
||||||
int_lit.value() as u32
|
None => i as u32,
|
||||||
},
|
_ => panic!("Enums may only have number literal values"),
|
||||||
None => i as u32,
|
};
|
||||||
_ => panic!("Enums may only have number literal values")
|
|
||||||
};
|
|
||||||
|
|
||||||
Variant {
|
Variant {
|
||||||
name: v.ident,
|
name: v.ident,
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
}).collect();
|
})
|
||||||
|
.collect();
|
||||||
self.enums.push(Enum {
|
self.enums.push(Enum {
|
||||||
name: item.ident,
|
name: item.ident,
|
||||||
variants
|
variants,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,20 +290,17 @@ impl Program {
|
|||||||
_ => panic!("only foreign functions/types allowed for now"),
|
_ => panic!("only foreign functions/types allowed for now"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.imports.push(Import { module, js_namespace, kind });
|
self.imports.push(Import {
|
||||||
|
module,
|
||||||
|
js_namespace,
|
||||||
|
kind,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_foreign_fn(&mut self, f: syn::ForeignItemFn, opts: BindgenAttrs)
|
pub fn push_foreign_fn(&mut self, f: syn::ForeignItemFn, opts: BindgenAttrs) -> ImportKind {
|
||||||
-> ImportKind
|
|
||||||
{
|
|
||||||
let js_name = opts.js_name().unwrap_or(f.ident);
|
let js_name = opts.js_name().unwrap_or(f.ident);
|
||||||
let mut wasm = Function::from_decl(js_name,
|
let mut wasm = Function::from_decl(js_name, f.decl, f.attrs, opts, f.vis, false).0;
|
||||||
f.decl,
|
|
||||||
f.attrs,
|
|
||||||
opts,
|
|
||||||
f.vis,
|
|
||||||
false).0;
|
|
||||||
if wasm.opts.catch() {
|
if wasm.opts.catch() {
|
||||||
// TODO: this assumes a whole bunch:
|
// TODO: this assumes a whole bunch:
|
||||||
//
|
//
|
||||||
@ -308,20 +314,19 @@ impl Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let kind = if wasm.opts.method() {
|
let kind = if wasm.opts.method() {
|
||||||
let class = wasm.arguments.get(0)
|
let class = wasm.arguments
|
||||||
|
.get(0)
|
||||||
.expect("methods must have at least one argument");
|
.expect("methods must have at least one argument");
|
||||||
let class = match *class {
|
let class = match *class {
|
||||||
Type::ByRef(ref t) |
|
Type::ByRef(ref t) | Type::ByValue(ref t) => t,
|
||||||
Type::ByValue(ref t) => t,
|
Type::ByMutRef(_) => panic!("first method argument cannot be mutable ref"),
|
||||||
Type::ByMutRef(_) => {
|
Type::Vector(..) => panic!("method receivers cannot be vectors"),
|
||||||
panic!("first method argument cannot be mutable ref")
|
|
||||||
}
|
|
||||||
Type::Vector(..) => {
|
|
||||||
panic!("method receivers cannot be vectors")
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let class_name = match *class {
|
let class_name = match *class {
|
||||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => path,
|
syn::Type::Path(syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) => path,
|
||||||
_ => panic!("first argument of method must be a path"),
|
_ => panic!("first argument of method must be a path"),
|
||||||
};
|
};
|
||||||
let class_name = extract_path_ident(class_name)
|
let class_name = extract_path_ident(class_name)
|
||||||
@ -337,7 +342,10 @@ impl Program {
|
|||||||
_ => panic!("constructor returns must be bare types"),
|
_ => panic!("constructor returns must be bare types"),
|
||||||
};
|
};
|
||||||
let class_name = match *class {
|
let class_name = match *class {
|
||||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => path,
|
syn::Type::Path(syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) => path,
|
||||||
_ => panic!("first argument of method must be a path"),
|
_ => panic!("first argument of method must be a path"),
|
||||||
};
|
};
|
||||||
let class_name = extract_path_ident(class_name)
|
let class_name = extract_path_ident(class_name)
|
||||||
@ -367,20 +375,18 @@ impl Program {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_foreign_ty(&mut self, f: syn::ForeignItemType)
|
pub fn push_foreign_ty(&mut self, f: syn::ForeignItemType) -> ImportKind {
|
||||||
-> ImportKind
|
|
||||||
{
|
|
||||||
ImportKind::Type(ImportType {
|
ImportKind::Type(ImportType {
|
||||||
vis: f.vis,
|
vis: f.vis,
|
||||||
name: f.ident
|
name: f.ident,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_foreign_static(&mut self,
|
pub fn push_foreign_static(
|
||||||
f: syn::ForeignItemStatic,
|
&mut self,
|
||||||
opts: BindgenAttrs)
|
f: syn::ForeignItemStatic,
|
||||||
-> ImportKind
|
opts: BindgenAttrs,
|
||||||
{
|
) -> ImportKind {
|
||||||
if f.mutability.is_some() {
|
if f.mutability.is_some() {
|
||||||
panic!("cannot import mutable globals yet")
|
panic!("cannot import mutable globals yet")
|
||||||
}
|
}
|
||||||
@ -427,20 +433,17 @@ impl Function {
|
|||||||
panic!("can only bindgen safe functions");
|
panic!("can only bindgen safe functions");
|
||||||
}
|
}
|
||||||
|
|
||||||
Function::from_decl(input.ident,
|
Function::from_decl(input.ident, input.decl, input.attrs, opts, input.vis, false).0
|
||||||
input.decl,
|
|
||||||
input.attrs,
|
|
||||||
opts,
|
|
||||||
input.vis,
|
|
||||||
false).0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_decl(name: syn::Ident,
|
pub fn from_decl(
|
||||||
decl: Box<syn::FnDecl>,
|
name: syn::Ident,
|
||||||
attrs: Vec<syn::Attribute>,
|
decl: Box<syn::FnDecl>,
|
||||||
opts: BindgenAttrs,
|
attrs: Vec<syn::Attribute>,
|
||||||
vis: syn::Visibility,
|
opts: BindgenAttrs,
|
||||||
allow_self: bool) -> (Function, Option<bool>) {
|
vis: syn::Visibility,
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
@ -449,20 +452,19 @@ impl Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut mutable = None;
|
let mut mutable = None;
|
||||||
let arguments = decl.inputs.iter()
|
let arguments = decl.inputs
|
||||||
.filter_map(|arg| {
|
.iter()
|
||||||
match *arg {
|
.filter_map(|arg| match *arg {
|
||||||
syn::FnArg::Captured(ref c) => Some(c),
|
syn::FnArg::Captured(ref c) => Some(c),
|
||||||
syn::FnArg::SelfValue(_) => {
|
syn::FnArg::SelfValue(_) => {
|
||||||
panic!("by-value `self` not yet supported");
|
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"),
|
|
||||||
}
|
}
|
||||||
|
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"),
|
||||||
})
|
})
|
||||||
.map(|arg| Type::from(&arg.ty))
|
.map(|arg| Type::from(&arg.ty))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -472,24 +474,27 @@ impl Function {
|
|||||||
syn::ReturnType::Type(_, ref t) => Some(Type::from(t)),
|
syn::ReturnType::Type(_, ref t) => Some(Type::from(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
(Function {
|
(
|
||||||
name,
|
Function {
|
||||||
arguments,
|
name,
|
||||||
ret,
|
arguments,
|
||||||
opts,
|
ret,
|
||||||
rust_vis: vis,
|
opts,
|
||||||
rust_decl: decl,
|
rust_vis: vis,
|
||||||
rust_attrs: attrs,
|
rust_decl: decl,
|
||||||
}, mutable)
|
rust_attrs: attrs,
|
||||||
|
},
|
||||||
|
mutable,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_path_ident(path: &syn::Path) -> Option<syn::Ident> {
|
pub fn extract_path_ident(path: &syn::Path) -> Option<syn::Ident> {
|
||||||
if path.leading_colon.is_some() {
|
if path.leading_colon.is_some() {
|
||||||
return None
|
return None;
|
||||||
}
|
}
|
||||||
if path.segments.len() != 1 {
|
if path.segments.len() != 1 {
|
||||||
return None
|
return None;
|
||||||
}
|
}
|
||||||
match path.segments.first().unwrap().value().arguments {
|
match path.segments.first().unwrap().value().arguments {
|
||||||
syn::PathArguments::None => {}
|
syn::PathArguments::None => {}
|
||||||
@ -503,7 +508,10 @@ impl Type {
|
|||||||
match *ty {
|
match *ty {
|
||||||
syn::Type::Reference(ref r) => {
|
syn::Type::Reference(ref r) => {
|
||||||
match *r.elem {
|
match *r.elem {
|
||||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
syn::Type::Path(syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) => {
|
||||||
let ident = extract_path_ident(path);
|
let ident = extract_path_ident(path);
|
||||||
match ident.as_ref().map(|s| s.as_ref()) {
|
match ident.as_ref().map(|s| s.as_ref()) {
|
||||||
Some("str") => return Type::Vector(VectorType::String, false),
|
Some("str") => return Type::Vector(VectorType::String, false),
|
||||||
@ -512,7 +520,7 @@ impl Type {
|
|||||||
}
|
}
|
||||||
syn::Type::Slice(ref slice) => {
|
syn::Type::Slice(ref slice) => {
|
||||||
if let Some(ty) = VectorType::from(&slice.elem) {
|
if let Some(ty) = VectorType::from(&slice.elem) {
|
||||||
return Type::Vector(ty, false)
|
return Type::Vector(ty, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -521,26 +529,26 @@ impl Type {
|
|||||||
Type::ByMutRef((*r.elem).clone())
|
Type::ByMutRef((*r.elem).clone())
|
||||||
} else {
|
} else {
|
||||||
Type::ByRef((*r.elem).clone())
|
Type::ByRef((*r.elem).clone())
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
syn::Type::Path(syn::TypePath { qself: None, ref path })
|
syn::Type::Path(syn::TypePath {
|
||||||
if path.leading_colon.is_none() && path.segments.len() == 1 =>
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) if path.leading_colon.is_none() && path.segments.len() == 1 =>
|
||||||
{
|
{
|
||||||
let seg = path.segments.first().unwrap().into_value();
|
let seg = path.segments.first().unwrap().into_value();
|
||||||
match seg.arguments {
|
match seg.arguments {
|
||||||
syn::PathArguments::None => {
|
syn::PathArguments::None => match seg.ident.as_ref() {
|
||||||
match seg.ident.as_ref() {
|
"String" => return Type::Vector(VectorType::String, true),
|
||||||
"String" => return Type::Vector(VectorType::String, true),
|
_ => {}
|
||||||
_ => {}
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
syn::PathArguments::AngleBracketed(ref t)
|
syn::PathArguments::AngleBracketed(ref t)
|
||||||
if seg.ident == "Vec" && t.args.len() == 1 =>
|
if seg.ident == "Vec" && t.args.len() == 1 =>
|
||||||
{
|
{
|
||||||
match **t.args.first().unwrap().value() {
|
match **t.args.first().unwrap().value() {
|
||||||
syn::GenericArgument::Type(ref t) => {
|
syn::GenericArgument::Type(ref t) => {
|
||||||
if let Some(ty) = VectorType::from(t) {
|
if let Some(ty) = VectorType::from(t) {
|
||||||
return Type::Vector(ty, true)
|
return Type::Vector(ty, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -571,14 +579,9 @@ impl Export {
|
|||||||
pub fn export_name(&self) -> syn::LitStr {
|
pub fn export_name(&self) -> syn::LitStr {
|
||||||
let name = match self.class {
|
let name = match self.class {
|
||||||
Some(class) => {
|
Some(class) => {
|
||||||
shared::struct_function_export_name(
|
shared::struct_function_export_name(class.as_ref(), self.function.name.as_ref())
|
||||||
class.as_ref(),
|
|
||||||
self.function.name.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
shared::free_function_export_name(self.function.name.as_ref())
|
|
||||||
}
|
}
|
||||||
|
None => shared::free_function_export_name(self.function.name.as_ref()),
|
||||||
};
|
};
|
||||||
syn::LitStr::new(&name, Span::def_site())
|
syn::LitStr::new(&name, Span::def_site())
|
||||||
}
|
}
|
||||||
@ -609,7 +612,8 @@ pub struct BindgenAttrs {
|
|||||||
|
|
||||||
impl BindgenAttrs {
|
impl BindgenAttrs {
|
||||||
pub fn find(attrs: &mut Vec<syn::Attribute>) -> BindgenAttrs {
|
pub fn find(attrs: &mut Vec<syn::Attribute>) -> BindgenAttrs {
|
||||||
let pos = attrs.iter()
|
let pos = attrs
|
||||||
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|&(_, ref m)| m.path.segments[0].ident == "wasm_bindgen")
|
.find(|&(_, ref m)| m.path.segments[0].ident == "wasm_bindgen")
|
||||||
.map(|a| a.0);
|
.map(|a| a.0);
|
||||||
@ -617,101 +621,83 @@ impl BindgenAttrs {
|
|||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
None => return BindgenAttrs::default(),
|
None => return BindgenAttrs::default(),
|
||||||
};
|
};
|
||||||
syn::parse(attrs.remove(pos).tts.into())
|
syn::parse(attrs.remove(pos).tts.into()).expect("malformed #[wasm_bindgen] attribute")
|
||||||
.expect("malformed #[wasm_bindgen] attribute")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module(&self) -> Option<&str> {
|
fn module(&self) -> Option<&str> {
|
||||||
self.attrs.iter()
|
self.attrs
|
||||||
.filter_map(|a| {
|
.iter()
|
||||||
match *a {
|
.filter_map(|a| match *a {
|
||||||
BindgenAttr::Module(ref s) => Some(&s[..]),
|
BindgenAttr::Module(ref s) => Some(&s[..]),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn catch(&self) -> bool {
|
pub fn catch(&self) -> bool {
|
||||||
self.attrs.iter()
|
self.attrs.iter().any(|a| match *a {
|
||||||
.any(|a| {
|
BindgenAttr::Catch => true,
|
||||||
match *a {
|
_ => false,
|
||||||
BindgenAttr::Catch => true,
|
})
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constructor(&self) -> bool {
|
fn constructor(&self) -> bool {
|
||||||
self.attrs.iter()
|
self.attrs.iter().any(|a| match *a {
|
||||||
.any(|a| {
|
BindgenAttr::Constructor => true,
|
||||||
match *a {
|
_ => false,
|
||||||
BindgenAttr::Constructor => true,
|
})
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn method(&self) -> bool {
|
fn method(&self) -> bool {
|
||||||
self.attrs.iter()
|
self.attrs.iter().any(|a| match *a {
|
||||||
.any(|a| {
|
BindgenAttr::Method => true,
|
||||||
match *a {
|
_ => false,
|
||||||
BindgenAttr::Method => true,
|
})
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn js_namespace(&self) -> Option<syn::Ident> {
|
fn js_namespace(&self) -> Option<syn::Ident> {
|
||||||
self.attrs.iter()
|
self.attrs
|
||||||
.filter_map(|a| {
|
.iter()
|
||||||
match *a {
|
.filter_map(|a| match *a {
|
||||||
BindgenAttr::JsNamespace(s) => Some(s),
|
BindgenAttr::JsNamespace(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getter(&self) -> Option<Option<syn::Ident>> {
|
pub fn getter(&self) -> Option<Option<syn::Ident>> {
|
||||||
self.attrs.iter()
|
self.attrs
|
||||||
.filter_map(|a| {
|
.iter()
|
||||||
match *a {
|
.filter_map(|a| match *a {
|
||||||
BindgenAttr::Getter(s) => Some(s),
|
BindgenAttr::Getter(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setter(&self) -> Option<Option<syn::Ident>> {
|
pub fn setter(&self) -> Option<Option<syn::Ident>> {
|
||||||
self.attrs.iter()
|
self.attrs
|
||||||
.filter_map(|a| {
|
.iter()
|
||||||
match *a {
|
.filter_map(|a| match *a {
|
||||||
BindgenAttr::Setter(s) => Some(s),
|
BindgenAttr::Setter(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn structural(&self) -> bool {
|
pub fn structural(&self) -> bool {
|
||||||
self.attrs.iter()
|
self.attrs.iter().any(|a| match *a {
|
||||||
.any(|a| {
|
BindgenAttr::Structural => true,
|
||||||
match *a {
|
_ => false,
|
||||||
BindgenAttr::Structural => true,
|
})
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn js_name(&self) -> Option<syn::Ident> {
|
pub fn js_name(&self) -> Option<syn::Ident> {
|
||||||
self.attrs.iter()
|
self.attrs
|
||||||
.filter_map(|a| {
|
.iter()
|
||||||
match *a {
|
.filter_map(|a| match *a {
|
||||||
BindgenAttr::JsName(s) => Some(s),
|
BindgenAttr::JsName(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
@ -800,14 +786,17 @@ impl syn::synom::Synom for BindgenAttr {
|
|||||||
fn extract_first_ty_param(ty: Option<&Type>) -> Option<Option<Type>> {
|
fn extract_first_ty_param(ty: Option<&Type>) -> Option<Option<Type>> {
|
||||||
let ty = match ty {
|
let ty = match ty {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => return Some(None)
|
None => return Some(None),
|
||||||
};
|
};
|
||||||
let ty = match *ty {
|
let ty = match *ty {
|
||||||
Type::ByValue(ref t) => t,
|
Type::ByValue(ref t) => t,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let path = match *ty {
|
let path = match *ty {
|
||||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => path,
|
syn::Type::Path(syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) => path,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let seg = path.segments.last()?.into_value();
|
let seg = path.segments.last()?.into_value();
|
||||||
@ -826,12 +815,10 @@ fn extract_first_ty_param(ty: Option<&Type>) -> Option<Option<Type>> {
|
|||||||
Some(Some(Type::from(ty)))
|
Some(Some(Type::from(ty)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn term<'a>(cursor: syn::buffer::Cursor<'a>, name: &str)
|
fn term<'a>(cursor: syn::buffer::Cursor<'a>, name: &str) -> syn::synom::PResult<'a, ()> {
|
||||||
-> syn::synom::PResult<'a, ()>
|
|
||||||
{
|
|
||||||
if let Some((_span, term, next)) = cursor.term() {
|
if let Some((_span, term, next)) = cursor.term() {
|
||||||
if term.as_str() == name {
|
if term.as_str() == name {
|
||||||
return Ok(((), next))
|
return Ok(((), next));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syn::parse_error()
|
syn::parse_error()
|
||||||
@ -847,7 +834,10 @@ fn ungroup(input: &syn::Type) -> &syn::Type {
|
|||||||
impl VectorType {
|
impl VectorType {
|
||||||
fn from(ty: &syn::Type) -> Option<VectorType> {
|
fn from(ty: &syn::Type) -> Option<VectorType> {
|
||||||
let path = match *ungroup(ty) {
|
let path = match *ungroup(ty) {
|
||||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => path,
|
syn::Type::Path(syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) => path,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
match extract_path_ident(path)?.as_ref() {
|
match extract_path_ident(path)?.as_ref() {
|
621
crates/backend/src/codegen.rs
Normal file
621
crates/backend/src/codegen.rs
Normal file
@ -0,0 +1,621 @@
|
|||||||
|
use ast;
|
||||||
|
use quote::{ToTokens, Tokens};
|
||||||
|
use proc_macro2::Span;
|
||||||
|
use shared;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::env;
|
||||||
|
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
|
||||||
|
use syn;
|
||||||
|
|
||||||
|
fn to_ident_name(s: &str) -> Cow<str> {
|
||||||
|
if s.chars().all(|c| match c {
|
||||||
|
'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => true,
|
||||||
|
_ => false,
|
||||||
|
}) {
|
||||||
|
return Cow::from(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cow::from(
|
||||||
|
s.chars()
|
||||||
|
.map(|c| match c {
|
||||||
|
'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => c,
|
||||||
|
_ => '_',
|
||||||
|
})
|
||||||
|
.collect::<String>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ast::Program {
|
||||||
|
// Generate wrappers for all the items that we've found
|
||||||
|
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||||
|
for export in self.exports.iter() {
|
||||||
|
export.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
for s in self.structs.iter() {
|
||||||
|
s.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
let mut types = HashSet::new();
|
||||||
|
for i in self.imports.iter() {
|
||||||
|
if let ast::ImportKind::Type(ref t) = i.kind {
|
||||||
|
types.insert(t.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i in self.imports.iter() {
|
||||||
|
match i.js_namespace {
|
||||||
|
Some(ns) if types.contains(&ns) => {
|
||||||
|
let kind = &i.kind;
|
||||||
|
(quote! { impl #ns { #kind } }).to_tokens(tokens);
|
||||||
|
}
|
||||||
|
_ => i.kind.to_tokens(tokens),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for e in self.enums.iter() {
|
||||||
|
e.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 we'll
|
||||||
|
// eventually have it actually in its own section.
|
||||||
|
|
||||||
|
static CNT: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||||
|
|
||||||
|
let crate_name = env::var("CARGO_PKG_NAME").expect("should have CARGO_PKG_NAME env var");
|
||||||
|
let crate_vers =
|
||||||
|
env::var("CARGO_PKG_VERSION").expect("should have CARGO_PKG_VERSION env var");
|
||||||
|
|
||||||
|
let generated_static_name = format!(
|
||||||
|
"__WASM_BINDGEN_GENERATED_{}_{}_{}",
|
||||||
|
to_ident_name(&crate_name),
|
||||||
|
to_ident_name(&crate_vers),
|
||||||
|
CNT.fetch_add(1, Ordering::SeqCst)
|
||||||
|
);
|
||||||
|
let generated_static_name = syn::Ident::from(generated_static_name);
|
||||||
|
|
||||||
|
let mut generated_static_value = Tokens::new();
|
||||||
|
let generated_static_length = self.literal(&mut generated_static_value);
|
||||||
|
|
||||||
|
(my_quote! {
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
#[wasm_custom_section = "__wasm_bindgen_unstable"]
|
||||||
|
const #generated_static_name: [u8; #generated_static_length] =
|
||||||
|
[#generated_static_value];
|
||||||
|
}).to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ast::Struct {
|
||||||
|
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||||
|
let name = &self.name;
|
||||||
|
let free_fn = syn::Ident::from(shared::free_function(self.name.as_ref()));
|
||||||
|
let c = shared::name_to_descriptor(name.as_ref()) as u32;
|
||||||
|
(my_quote! {
|
||||||
|
impl ::wasm_bindgen::convert::WasmBoundary for #name {
|
||||||
|
type Js = u32;
|
||||||
|
const DESCRIPTOR: u32 = #c;
|
||||||
|
|
||||||
|
fn into_js(self) -> u32 {
|
||||||
|
Box::into_raw(Box::new(::wasm_bindgen::__rt::WasmRefCell::new(self))) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_js(js: u32) -> Self {
|
||||||
|
let js = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>;
|
||||||
|
::wasm_bindgen::__rt::assert_not_null(js);
|
||||||
|
let js = Box::from_raw(js);
|
||||||
|
js.borrow_mut(); // make sure no one's borrowing
|
||||||
|
js.into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::wasm_bindgen::convert::FromRefWasmBoundary for #name {
|
||||||
|
type RefAnchor = ::wasm_bindgen::__rt::Ref<'static, #name>;
|
||||||
|
unsafe fn from_js_ref(js: Self::Js) -> Self::RefAnchor {
|
||||||
|
let js = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>;
|
||||||
|
::wasm_bindgen::__rt::assert_not_null(js);
|
||||||
|
(*js).borrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::wasm_bindgen::convert::FromRefMutWasmBoundary for #name {
|
||||||
|
type RefAnchor = ::wasm_bindgen::__rt::RefMut<'static, #name>;
|
||||||
|
|
||||||
|
unsafe fn from_js_ref_mut(js: Self::Js) -> Self::RefAnchor {
|
||||||
|
let js = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>;
|
||||||
|
::wasm_bindgen::__rt::assert_not_null(js);
|
||||||
|
(*js).borrow_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern fn #free_fn(ptr: u32) {
|
||||||
|
<#name as ::wasm_bindgen::convert::WasmBoundary>::from_js(ptr);
|
||||||
|
}
|
||||||
|
}).to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ast::Export {
|
||||||
|
fn to_tokens(self: &ast::Export, into: &mut Tokens) {
|
||||||
|
let generated_name = self.rust_symbol();
|
||||||
|
let export_name = self.export_name();
|
||||||
|
let mut args = vec![];
|
||||||
|
let mut arg_conversions = vec![];
|
||||||
|
let mut converted_arguments = vec![];
|
||||||
|
let ret = syn::Ident::from("_ret");
|
||||||
|
|
||||||
|
let mut offset = 0;
|
||||||
|
if self.method {
|
||||||
|
let class = self.class.unwrap();
|
||||||
|
args.push(my_quote! { me: *mut ::wasm_bindgen::__rt::WasmRefCell<#class> });
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
::wasm_bindgen::__rt::assert_not_null(me);
|
||||||
|
let me = unsafe { &*me };
|
||||||
|
});
|
||||||
|
offset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, ty) in self.function.arguments.iter().enumerate() {
|
||||||
|
let i = i + offset;
|
||||||
|
let ident = syn::Ident::from(format!("arg{}", i));
|
||||||
|
match *ty {
|
||||||
|
ast::Type::Vector(ref ty, owned) => {
|
||||||
|
let ptr = syn::Ident::from(format!("arg{}_ptr", i));
|
||||||
|
let len = syn::Ident::from(format!("arg{}_len", i));
|
||||||
|
let abi_ty = ty.abi_element();
|
||||||
|
args.push(my_quote! { #ptr: *mut #abi_ty });
|
||||||
|
args.push(my_quote! { #len: usize });
|
||||||
|
if owned {
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #ident = unsafe {
|
||||||
|
::std::vec::Vec::from_raw_parts(#ptr, #len, #len)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #ident = unsafe {
|
||||||
|
::std::slice::from_raw_parts(#ptr as *const #abi_ty, #len)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let ast::VectorType::String = *ty {
|
||||||
|
if owned {
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #ident = unsafe {
|
||||||
|
::std::string::String::from_utf8_unchecked(#ident)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #ident = unsafe {
|
||||||
|
::std::str::from_utf8_unchecked(#ident)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::Type::ByValue(ref t) => {
|
||||||
|
args.push(my_quote! {
|
||||||
|
#ident: <#t as ::wasm_bindgen::convert::WasmBoundary >::Js
|
||||||
|
});
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #ident = unsafe {
|
||||||
|
<#t as ::wasm_bindgen::convert::WasmBoundary>
|
||||||
|
::from_js(#ident)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ast::Type::ByRef(ref ty) => {
|
||||||
|
args.push(my_quote! {
|
||||||
|
#ident: <#ty as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||||
|
});
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #ident = unsafe {
|
||||||
|
<#ty as ::wasm_bindgen::convert::FromRefWasmBoundary>
|
||||||
|
::from_js_ref(#ident)
|
||||||
|
};
|
||||||
|
let #ident = &*#ident;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ast::Type::ByMutRef(ref ty) => {
|
||||||
|
args.push(my_quote! {
|
||||||
|
#ident: <#ty as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||||
|
});
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let mut #ident = unsafe {
|
||||||
|
<#ty as ::wasm_bindgen::convert::FromRefMutWasmBoundary>
|
||||||
|
::from_js_ref_mut(#ident)
|
||||||
|
};
|
||||||
|
let #ident = &mut *#ident;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
converted_arguments.push(my_quote! { #ident });
|
||||||
|
}
|
||||||
|
let ret_ty;
|
||||||
|
let convert_ret;
|
||||||
|
match self.function.ret {
|
||||||
|
Some(ast::Type::Vector(ref ty, true)) => {
|
||||||
|
ret_ty = my_quote! { -> *mut #ty };
|
||||||
|
convert_ret = my_quote! { Box::into_raw(Box::new(#ret)) };
|
||||||
|
}
|
||||||
|
Some(ast::Type::ByValue(ref t)) => {
|
||||||
|
ret_ty = my_quote! {
|
||||||
|
-> <#t as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||||
|
};
|
||||||
|
convert_ret = my_quote! {
|
||||||
|
<#t as ::wasm_bindgen::convert::WasmBoundary>::into_js(#ret)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Some(ast::Type::Vector(_, false))
|
||||||
|
| Some(ast::Type::ByMutRef(_))
|
||||||
|
| Some(ast::Type::ByRef(_)) => {
|
||||||
|
panic!("can't return a borrowed ref");
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
ret_ty = my_quote!{};
|
||||||
|
convert_ret = my_quote!{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = self.function.name;
|
||||||
|
let receiver = match self.class {
|
||||||
|
Some(_) if self.method => {
|
||||||
|
if self.mutable {
|
||||||
|
my_quote! { me.borrow_mut().#name }
|
||||||
|
} else {
|
||||||
|
my_quote! { me.borrow().#name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(class) => my_quote! { #class::#name },
|
||||||
|
None => my_quote!{ #name },
|
||||||
|
};
|
||||||
|
|
||||||
|
let tokens = my_quote! {
|
||||||
|
#[export_name = #export_name]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub extern fn #generated_name(#(#args),*) #ret_ty {
|
||||||
|
::wasm_bindgen::__rt::link_this_library();
|
||||||
|
#(#arg_conversions)*
|
||||||
|
let #ret = #receiver(#(#converted_arguments),*);
|
||||||
|
#convert_ret
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tokens.to_tokens(into);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ast::ImportType {
|
||||||
|
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||||
|
let vis = &self.vis;
|
||||||
|
let name = &self.name;
|
||||||
|
(my_quote! {
|
||||||
|
#[allow(bad_style)]
|
||||||
|
#vis struct #name {
|
||||||
|
obj: ::wasm_bindgen::JsValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::wasm_bindgen::convert::WasmBoundary for #name {
|
||||||
|
type Js = <::wasm_bindgen::JsValue as
|
||||||
|
::wasm_bindgen::convert::WasmBoundary>::Js;
|
||||||
|
const DESCRIPTOR: u32 = <::wasm_bindgen::JsValue as
|
||||||
|
::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR;
|
||||||
|
|
||||||
|
fn into_js(self) -> Self::Js {
|
||||||
|
self.obj.into_js()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_js(js: Self::Js) -> Self {
|
||||||
|
#name { obj: ::wasm_bindgen::JsValue::from_js(js) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::wasm_bindgen::convert::ToRefWasmBoundary for #name {
|
||||||
|
fn to_js_ref(&self) -> u32 {
|
||||||
|
self.obj.to_js_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
fn from(obj: ::wasm_bindgen::JsValue) -> #name {
|
||||||
|
#name { obj }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<#name> for ::wasm_bindgen::JsValue {
|
||||||
|
fn from(obj: #name) -> ::wasm_bindgen::JsValue {
|
||||||
|
obj.obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ast::ImportKind {
|
||||||
|
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||||
|
match *self {
|
||||||
|
ast::ImportKind::Function(ref f) => f.to_tokens(tokens),
|
||||||
|
ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
|
||||||
|
ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ast::ImportFunction {
|
||||||
|
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||||
|
let mut class_ty = None;
|
||||||
|
let mut is_method = false;
|
||||||
|
match self.kind {
|
||||||
|
ast::ImportFunctionKind::Method { ref ty, .. } => {
|
||||||
|
is_method = true;
|
||||||
|
class_ty = Some(ty);
|
||||||
|
}
|
||||||
|
ast::ImportFunctionKind::JsConstructor { ref ty, .. } => {
|
||||||
|
class_ty = Some(ty);
|
||||||
|
}
|
||||||
|
ast::ImportFunctionKind::Normal => {}
|
||||||
|
}
|
||||||
|
let vis = &self.function.rust_vis;
|
||||||
|
let ret = &self.function.rust_decl.output;
|
||||||
|
let fn_token = &self.function.rust_decl.fn_token;
|
||||||
|
|
||||||
|
let mut abi_argument_names = Vec::new();
|
||||||
|
let mut abi_arguments = Vec::new();
|
||||||
|
let mut arg_conversions = Vec::new();
|
||||||
|
let ret_ident = syn::Ident::from("_ret");
|
||||||
|
|
||||||
|
let names = self.function
|
||||||
|
.rust_decl
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.map(|arg| match *arg {
|
||||||
|
syn::FnArg::Captured(ref c) => c,
|
||||||
|
_ => panic!("arguments cannot be `self` or ignored"),
|
||||||
|
})
|
||||||
|
.map(|arg| match arg.pat {
|
||||||
|
syn::Pat::Ident(syn::PatIdent {
|
||||||
|
by_ref: None,
|
||||||
|
ident,
|
||||||
|
subpat: None,
|
||||||
|
..
|
||||||
|
}) => ident,
|
||||||
|
_ => panic!("unsupported pattern in foreign function"),
|
||||||
|
});
|
||||||
|
|
||||||
|
for (i, (ty, name)) in self.function.arguments.iter().zip(names).enumerate() {
|
||||||
|
match *ty {
|
||||||
|
ast::Type::Vector(ref ty, owned) => {
|
||||||
|
let ptr = syn::Ident::from(format!("{}_ptr", name));
|
||||||
|
let len = syn::Ident::from(format!("{}_len", name));
|
||||||
|
abi_argument_names.push(ptr);
|
||||||
|
abi_argument_names.push(len);
|
||||||
|
let abi_ty = ty.abi_element();
|
||||||
|
abi_arguments.push(my_quote! { #ptr: *const #abi_ty });
|
||||||
|
abi_arguments.push(my_quote! { #len: usize });
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #ptr = #name.as_ptr();
|
||||||
|
let #len = #name.len();
|
||||||
|
});
|
||||||
|
if owned {
|
||||||
|
arg_conversions.push(my_quote! { ::std::mem::forget(#name); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::Type::ByValue(ref t) => {
|
||||||
|
abi_argument_names.push(name);
|
||||||
|
abi_arguments.push(my_quote! {
|
||||||
|
#name: <#t as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||||
|
});
|
||||||
|
if i == 0 && is_method {
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #name = <#t as ::wasm_bindgen::convert::WasmBoundary>
|
||||||
|
::into_js(self);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #name = <#t as ::wasm_bindgen::convert::WasmBoundary>
|
||||||
|
::into_js(#name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::Type::ByMutRef(_) => panic!("urgh mut"),
|
||||||
|
ast::Type::ByRef(ref t) => {
|
||||||
|
abi_argument_names.push(name);
|
||||||
|
abi_arguments.push(my_quote! { #name: u32 });
|
||||||
|
if i == 0 && is_method {
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #name = <#t as ::wasm_bindgen::convert::ToRefWasmBoundary>
|
||||||
|
::to_js_ref(self);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let #name = <#t as ::wasm_bindgen::convert::ToRefWasmBoundary>
|
||||||
|
::to_js_ref(#name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let abi_ret;
|
||||||
|
let mut convert_ret;
|
||||||
|
match self.function.ret {
|
||||||
|
Some(ast::Type::ByValue(ref t)) => {
|
||||||
|
abi_ret = my_quote! {
|
||||||
|
<#t as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||||
|
};
|
||||||
|
convert_ret = my_quote! {
|
||||||
|
<#t as ::wasm_bindgen::convert::WasmBoundary>::from_js(#ret_ident)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(ast::Type::Vector(ref ty, true)) => {
|
||||||
|
let name = syn::Ident::from("__ret_len");
|
||||||
|
let name_ptr = syn::Ident::from("__ret_len_ptr");
|
||||||
|
abi_argument_names.push(name_ptr);
|
||||||
|
abi_arguments.push(my_quote! { #name_ptr: *mut usize });
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let mut #name = 0;
|
||||||
|
let mut #name_ptr = &mut #name as *mut usize;
|
||||||
|
});
|
||||||
|
let abi_ty = ty.abi_element();
|
||||||
|
abi_ret = my_quote! { *mut #abi_ty };
|
||||||
|
if let ast::VectorType::String = *ty {
|
||||||
|
convert_ret = my_quote! {
|
||||||
|
String::from_utf8_unchecked(
|
||||||
|
Vec::from_raw_parts(#ret_ident, #name, #name)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
convert_ret = my_quote! {
|
||||||
|
Vec::from_raw_parts(#ret_ident, #name, #name)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(ast::Type::ByRef(_))
|
||||||
|
| Some(ast::Type::Vector(_, false))
|
||||||
|
| Some(ast::Type::ByMutRef(_)) => panic!("can't return a borrowed ref"),
|
||||||
|
None => {
|
||||||
|
abi_ret = my_quote! { () };
|
||||||
|
convert_ret = my_quote! { () };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut exceptional_ret = my_quote!{};
|
||||||
|
if self.function.opts.catch() {
|
||||||
|
let exn_data = syn::Ident::from("exn_data");
|
||||||
|
let exn_data_ptr = syn::Ident::from("exn_data_ptr");
|
||||||
|
abi_argument_names.push(exn_data_ptr);
|
||||||
|
abi_arguments.push(my_quote! { #exn_data_ptr: *mut u32 });
|
||||||
|
arg_conversions.push(my_quote! {
|
||||||
|
let mut #exn_data = [0; 2];
|
||||||
|
let #exn_data_ptr = #exn_data.as_mut_ptr();
|
||||||
|
});
|
||||||
|
convert_ret = my_quote! { Ok(#convert_ret) };
|
||||||
|
exceptional_ret = my_quote! {
|
||||||
|
if #exn_data[0] == 1 {
|
||||||
|
return Err(<::wasm_bindgen::JsValue as
|
||||||
|
::wasm_bindgen::convert::WasmBoundary>::from_js(#exn_data[1]))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let rust_name = self.rust_name;
|
||||||
|
let import_name = self.shim;
|
||||||
|
let attrs = &self.function.rust_attrs;
|
||||||
|
|
||||||
|
let arguments = self.function
|
||||||
|
.rust_decl
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.skip(if is_method { 1 } else { 0 })
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let me = if is_method {
|
||||||
|
my_quote! { &self, }
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let invocation = my_quote! {
|
||||||
|
#(#attrs)*
|
||||||
|
#[allow(bad_style)]
|
||||||
|
#vis extern #fn_token #rust_name(#me #(#arguments),*) #ret {
|
||||||
|
::wasm_bindgen::__rt::link_this_library();
|
||||||
|
#[wasm_import_module = "__wbindgen_placeholder__"]
|
||||||
|
extern {
|
||||||
|
fn #import_name(#(#abi_arguments),*) -> #abi_ret;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
#(#arg_conversions)*
|
||||||
|
let #ret_ident = #import_name(#(#abi_argument_names),*);
|
||||||
|
#exceptional_ret
|
||||||
|
#convert_ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(class) = class_ty {
|
||||||
|
(quote! {
|
||||||
|
impl #class {
|
||||||
|
#invocation
|
||||||
|
}
|
||||||
|
}).to_tokens(tokens);
|
||||||
|
} else {
|
||||||
|
invocation.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ast::Enum {
|
||||||
|
fn to_tokens(&self, into: &mut Tokens) {
|
||||||
|
let enum_name = &self.name;
|
||||||
|
let c = shared::TYPE_ENUM as u32;
|
||||||
|
let incoming_u32 = quote! { n };
|
||||||
|
let enum_name_as_string = enum_name.to_string();
|
||||||
|
let cast_clauses = self.variants.iter().map(|variant| {
|
||||||
|
let variant_name = &variant.name;
|
||||||
|
quote! {
|
||||||
|
if #incoming_u32 == #enum_name::#variant_name as u32 {
|
||||||
|
#enum_name::#variant_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
(my_quote! {
|
||||||
|
impl #enum_name {
|
||||||
|
fn from_u32(#incoming_u32: u32) -> #enum_name {
|
||||||
|
#(#cast_clauses else)* {
|
||||||
|
wasm_bindgen::throw(&format!("Could not cast {} as {}", #incoming_u32, #enum_name_as_string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::wasm_bindgen::convert::WasmBoundary for #enum_name {
|
||||||
|
type Js = u32;
|
||||||
|
const DESCRIPTOR: u32 = #c;
|
||||||
|
|
||||||
|
fn into_js(self) -> u32 {
|
||||||
|
self as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_js(js: u32) -> Self {
|
||||||
|
#enum_name::from_u32(js)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).to_tokens(into);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ast::ImportStatic {
|
||||||
|
fn to_tokens(&self, into: &mut Tokens) {
|
||||||
|
let name = self.rust_name;
|
||||||
|
let ty = &self.ty;
|
||||||
|
let shim_name = self.shim;
|
||||||
|
let vis = &self.vis;
|
||||||
|
(my_quote! {
|
||||||
|
#[allow(bad_style)]
|
||||||
|
#vis static #name: ::wasm_bindgen::JsStatic<#ty> = {
|
||||||
|
fn init() -> #ty {
|
||||||
|
#[wasm_import_module = "__wbindgen_placeholder__"]
|
||||||
|
extern {
|
||||||
|
fn #shim_name() -> u32;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
::wasm_bindgen::convert::WasmBoundary::from_js(#shim_name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::wasm_bindgen::JsStatic {
|
||||||
|
__inner: ::std::cell::UnsafeCell::new(None),
|
||||||
|
__init: init,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}).to_tokens(into);
|
||||||
|
}
|
||||||
|
}
|
25
crates/backend/src/lib.rs
Executable file
25
crates/backend/src/lib.rs
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#![recursion_limit = "128"]
|
||||||
|
|
||||||
|
extern crate proc_macro2;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate quote;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate syn;
|
||||||
|
|
||||||
|
extern crate wasm_bindgen_shared as shared;
|
||||||
|
|
||||||
|
macro_rules! my_quote {
|
||||||
|
($($t:tt)*) => (quote_spanned!(Span::call_site() => $($t)*))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod ast;
|
||||||
|
mod codegen;
|
||||||
|
mod literal;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
assert_eq!(2 + 2, 4);
|
||||||
|
}
|
||||||
|
}
|
@ -11,10 +11,7 @@ pub struct LiteralBuilder<'a> {
|
|||||||
|
|
||||||
impl<'a> LiteralBuilder<'a> {
|
impl<'a> LiteralBuilder<'a> {
|
||||||
pub fn new(dst: &'a mut Tokens) -> LiteralBuilder<'a> {
|
pub fn new(dst: &'a mut Tokens) -> LiteralBuilder<'a> {
|
||||||
LiteralBuilder {
|
LiteralBuilder { dst, cnt: 0 }
|
||||||
dst,
|
|
||||||
cnt: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(self) -> usize {
|
pub fn finish(self) -> usize {
|
||||||
@ -95,8 +92,9 @@ impl<'a> LiteralBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn list<T, F>(&mut self, list: T, mut cb: F)
|
fn list<T, F>(&mut self, list: T, mut cb: F)
|
||||||
where F: FnMut(T::Item, &mut Self),
|
where
|
||||||
T: IntoIterator,
|
F: FnMut(T::Item, &mut Self),
|
||||||
|
T: IntoIterator,
|
||||||
{
|
{
|
||||||
self.append("[");
|
self.append("[");
|
||||||
for (i, element) in list.into_iter().enumerate() {
|
for (i, element) in list.into_iter().enumerate() {
|
||||||
@ -316,8 +314,6 @@ impl Literal for ast::ImportStatic {
|
|||||||
|
|
||||||
impl Literal for ast::ImportType {
|
impl Literal for ast::ImportType {
|
||||||
fn literal(&self, a: &mut LiteralBuilder) {
|
fn literal(&self, a: &mut LiteralBuilder) {
|
||||||
a.fields(&[
|
a.fields(&[("kind", &|a| a.str("type"))])
|
||||||
("kind", &|a| a.str("type")),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,3 +19,4 @@ quote = '0.4'
|
|||||||
proc-macro2 = { version = "0.2", features = ["nightly"] }
|
proc-macro2 = { version = "0.2", features = ["nightly"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
wasm-bindgen-shared = { path = "../shared", version = "0.1.0" }
|
wasm-bindgen-shared = { path = "../shared", version = "0.1.0" }
|
||||||
|
wasm-bindgen-backend = { path = "../backend", version = "0.1.0" }
|
||||||
|
@ -1,40 +1,24 @@
|
|||||||
#![recursion_limit = "128"]
|
|
||||||
#![feature(proc_macro)]
|
#![feature(proc_macro)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
#[macro_use]
|
|
||||||
extern crate quote;
|
extern crate quote;
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
extern crate proc_macro2;
|
extern crate proc_macro2;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
extern crate wasm_bindgen_backend as backend;
|
||||||
extern crate wasm_bindgen_shared as shared;
|
extern crate wasm_bindgen_shared as shared;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::env;
|
|
||||||
use std::sync::atomic::*;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::Span;
|
use quote::{ToTokens, Tokens};
|
||||||
use quote::{Tokens, ToTokens};
|
|
||||||
|
|
||||||
macro_rules! my_quote {
|
|
||||||
($($t:tt)*) => (quote_spanned!(Span::call_site() => $($t)*))
|
|
||||||
}
|
|
||||||
|
|
||||||
mod ast;
|
|
||||||
mod literal;
|
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let item = syn::parse::<syn::Item>(input.clone())
|
let item = syn::parse::<syn::Item>(input.clone()).expect("expected a valid Rust item");
|
||||||
.expect("expected a valid Rust item");
|
let opts = syn::parse::<backend::ast::BindgenAttrs>(attr)
|
||||||
let opts = syn::parse::<ast::BindgenAttrs>(attr)
|
|
||||||
.expect("invalid arguments to #[wasm_bindgen]");
|
.expect("invalid arguments to #[wasm_bindgen]");
|
||||||
|
|
||||||
let mut ret = Tokens::new();
|
let mut ret = Tokens::new();
|
||||||
let mut program = ast::Program::default();
|
let mut program = backend::ast::Program::default();
|
||||||
program.push_item(item, Some(opts), &mut ret);
|
program.push_item(item, Some(opts), &mut ret);
|
||||||
program.to_tokens(&mut ret);
|
program.to_tokens(&mut ret);
|
||||||
|
|
||||||
@ -42,616 +26,3 @@ pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
ret.into()
|
ret.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_ident_name(s: &str) -> Cow<str> {
|
|
||||||
if s.chars().all(|c| match c {
|
|
||||||
'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => true,
|
|
||||||
_ => false,
|
|
||||||
}) {
|
|
||||||
return Cow::from(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
Cow::from(
|
|
||||||
s.chars()
|
|
||||||
.map(|c| match c {
|
|
||||||
'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => c,
|
|
||||||
_ => '_',
|
|
||||||
})
|
|
||||||
.collect::<String>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for ast::Program {
|
|
||||||
// Generate wrappers for all the items that we've found
|
|
||||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
|
||||||
for export in self.exports.iter() {
|
|
||||||
export.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
for s in self.structs.iter() {
|
|
||||||
s.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
let mut types = HashSet::new();
|
|
||||||
for i in self.imports.iter() {
|
|
||||||
if let ast::ImportKind::Type(ref t) = i.kind {
|
|
||||||
types.insert(t.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i in self.imports.iter() {
|
|
||||||
match i.js_namespace {
|
|
||||||
Some(ns) if types.contains(&ns) => {
|
|
||||||
let kind = &i.kind;
|
|
||||||
(quote! { impl #ns { #kind } }).to_tokens(tokens);
|
|
||||||
}
|
|
||||||
_ => i.kind.to_tokens(tokens),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for e in self.enums.iter() {
|
|
||||||
e.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 we'll
|
|
||||||
// eventually have it actually in its own section.
|
|
||||||
|
|
||||||
static CNT: AtomicUsize = ATOMIC_USIZE_INIT;
|
|
||||||
|
|
||||||
let crate_name = env::var("CARGO_PKG_NAME").expect("should have CARGO_PKG_NAME env var");
|
|
||||||
let crate_vers = env::var("CARGO_PKG_VERSION").expect("should have CARGO_PKG_VERSION env var");
|
|
||||||
|
|
||||||
let generated_static_name = format!(
|
|
||||||
"__WASM_BINDGEN_GENERATED_{}_{}_{}",
|
|
||||||
to_ident_name(&crate_name),
|
|
||||||
to_ident_name(&crate_vers),
|
|
||||||
CNT.fetch_add(1, Ordering::SeqCst)
|
|
||||||
);
|
|
||||||
let generated_static_name = syn::Ident::from(generated_static_name);
|
|
||||||
|
|
||||||
let mut generated_static_value = Tokens::new();
|
|
||||||
let generated_static_length = self.literal(&mut generated_static_value);
|
|
||||||
|
|
||||||
(my_quote! {
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
#[wasm_custom_section = "__wasm_bindgen_unstable"]
|
|
||||||
const #generated_static_name: [u8; #generated_static_length] =
|
|
||||||
[#generated_static_value];
|
|
||||||
}).to_tokens(tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for ast::Struct {
|
|
||||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
|
||||||
let name = &self.name;
|
|
||||||
let free_fn = syn::Ident::from(shared::free_function(self.name.as_ref()));
|
|
||||||
let c = shared::name_to_descriptor(name.as_ref()) as u32;
|
|
||||||
(my_quote! {
|
|
||||||
impl ::wasm_bindgen::convert::WasmBoundary for #name {
|
|
||||||
type Js = u32;
|
|
||||||
const DESCRIPTOR: u32 = #c;
|
|
||||||
|
|
||||||
fn into_js(self) -> u32 {
|
|
||||||
Box::into_raw(Box::new(::wasm_bindgen::__rt::WasmRefCell::new(self))) as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_js(js: u32) -> Self {
|
|
||||||
let js = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>;
|
|
||||||
::wasm_bindgen::__rt::assert_not_null(js);
|
|
||||||
let js = Box::from_raw(js);
|
|
||||||
js.borrow_mut(); // make sure no one's borrowing
|
|
||||||
js.into_inner()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::wasm_bindgen::convert::FromRefWasmBoundary for #name {
|
|
||||||
type RefAnchor = ::wasm_bindgen::__rt::Ref<'static, #name>;
|
|
||||||
unsafe fn from_js_ref(js: Self::Js) -> Self::RefAnchor {
|
|
||||||
let js = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>;
|
|
||||||
::wasm_bindgen::__rt::assert_not_null(js);
|
|
||||||
(*js).borrow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::wasm_bindgen::convert::FromRefMutWasmBoundary for #name {
|
|
||||||
type RefAnchor = ::wasm_bindgen::__rt::RefMut<'static, #name>;
|
|
||||||
|
|
||||||
unsafe fn from_js_ref_mut(js: Self::Js) -> Self::RefAnchor {
|
|
||||||
let js = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>;
|
|
||||||
::wasm_bindgen::__rt::assert_not_null(js);
|
|
||||||
(*js).borrow_mut()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern fn #free_fn(ptr: u32) {
|
|
||||||
<#name as ::wasm_bindgen::convert::WasmBoundary>::from_js(ptr);
|
|
||||||
}
|
|
||||||
}).to_tokens(tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for ast::Export {
|
|
||||||
fn to_tokens(self: &ast::Export, into: &mut Tokens) {
|
|
||||||
let generated_name = self.rust_symbol();
|
|
||||||
let export_name = self.export_name();
|
|
||||||
let mut args = vec![];
|
|
||||||
let mut arg_conversions = vec![];
|
|
||||||
let mut converted_arguments = vec![];
|
|
||||||
let ret = syn::Ident::from("_ret");
|
|
||||||
|
|
||||||
let mut offset = 0;
|
|
||||||
if self.method {
|
|
||||||
let class = self.class.unwrap();
|
|
||||||
args.push(my_quote! { me: *mut ::wasm_bindgen::__rt::WasmRefCell<#class> });
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
::wasm_bindgen::__rt::assert_not_null(me);
|
|
||||||
let me = unsafe { &*me };
|
|
||||||
});
|
|
||||||
offset = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i, ty) in self.function.arguments.iter().enumerate() {
|
|
||||||
let i = i + offset;
|
|
||||||
let ident = syn::Ident::from(format!("arg{}", i));
|
|
||||||
match *ty {
|
|
||||||
ast::Type::Vector(ref ty, owned) => {
|
|
||||||
let ptr = syn::Ident::from(format!("arg{}_ptr", i));
|
|
||||||
let len = syn::Ident::from(format!("arg{}_len", i));
|
|
||||||
let abi_ty = ty.abi_element();
|
|
||||||
args.push(my_quote! { #ptr: *mut #abi_ty });
|
|
||||||
args.push(my_quote! { #len: usize });
|
|
||||||
if owned {
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #ident = unsafe {
|
|
||||||
::std::vec::Vec::from_raw_parts(#ptr, #len, #len)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #ident = unsafe {
|
|
||||||
::std::slice::from_raw_parts(#ptr as *const #abi_ty, #len)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let ast::VectorType::String = *ty {
|
|
||||||
if owned {
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #ident = unsafe {
|
|
||||||
::std::string::String::from_utf8_unchecked(#ident)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #ident = unsafe {
|
|
||||||
::std::str::from_utf8_unchecked(#ident)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::Type::ByValue(ref t) => {
|
|
||||||
args.push(my_quote! {
|
|
||||||
#ident: <#t as ::wasm_bindgen::convert::WasmBoundary >::Js
|
|
||||||
});
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #ident = unsafe {
|
|
||||||
<#t as ::wasm_bindgen::convert::WasmBoundary>
|
|
||||||
::from_js(#ident)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ast::Type::ByRef(ref ty) => {
|
|
||||||
args.push(my_quote! {
|
|
||||||
#ident: <#ty as ::wasm_bindgen::convert::WasmBoundary>::Js
|
|
||||||
});
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #ident = unsafe {
|
|
||||||
<#ty as ::wasm_bindgen::convert::FromRefWasmBoundary>
|
|
||||||
::from_js_ref(#ident)
|
|
||||||
};
|
|
||||||
let #ident = &*#ident;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ast::Type::ByMutRef(ref ty) => {
|
|
||||||
args.push(my_quote! {
|
|
||||||
#ident: <#ty as ::wasm_bindgen::convert::WasmBoundary>::Js
|
|
||||||
});
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let mut #ident = unsafe {
|
|
||||||
<#ty as ::wasm_bindgen::convert::FromRefMutWasmBoundary>
|
|
||||||
::from_js_ref_mut(#ident)
|
|
||||||
};
|
|
||||||
let #ident = &mut *#ident;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
converted_arguments.push(my_quote! { #ident });
|
|
||||||
}
|
|
||||||
let ret_ty;
|
|
||||||
let convert_ret;
|
|
||||||
match self.function.ret {
|
|
||||||
Some(ast::Type::Vector(ref ty, true)) => {
|
|
||||||
ret_ty = my_quote! { -> *mut #ty };
|
|
||||||
convert_ret = my_quote! { Box::into_raw(Box::new(#ret)) };
|
|
||||||
}
|
|
||||||
Some(ast::Type::ByValue(ref t)) => {
|
|
||||||
ret_ty = my_quote! {
|
|
||||||
-> <#t as ::wasm_bindgen::convert::WasmBoundary>::Js
|
|
||||||
};
|
|
||||||
convert_ret = my_quote! {
|
|
||||||
<#t as ::wasm_bindgen::convert::WasmBoundary>::into_js(#ret)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Some(ast::Type::Vector(_, false)) |
|
|
||||||
Some(ast::Type::ByMutRef(_)) |
|
|
||||||
Some(ast::Type::ByRef(_)) => {
|
|
||||||
panic!("can't return a borrowed ref");
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
ret_ty = my_quote! {};
|
|
||||||
convert_ret = my_quote! {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = self.function.name;
|
|
||||||
let receiver = match self.class {
|
|
||||||
Some(_) if self.method => {
|
|
||||||
if self.mutable {
|
|
||||||
my_quote! { me.borrow_mut().#name }
|
|
||||||
} else {
|
|
||||||
my_quote! { me.borrow().#name }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(class) => my_quote! { #class::#name },
|
|
||||||
None => my_quote!{ #name },
|
|
||||||
};
|
|
||||||
|
|
||||||
let tokens = my_quote! {
|
|
||||||
#[export_name = #export_name]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub extern fn #generated_name(#(#args),*) #ret_ty {
|
|
||||||
::wasm_bindgen::__rt::link_this_library();
|
|
||||||
#(#arg_conversions)*
|
|
||||||
let #ret = #receiver(#(#converted_arguments),*);
|
|
||||||
#convert_ret
|
|
||||||
}
|
|
||||||
};
|
|
||||||
tokens.to_tokens(into);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for ast::ImportType {
|
|
||||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
|
||||||
let vis = &self.vis;
|
|
||||||
let name = &self.name;
|
|
||||||
(my_quote! {
|
|
||||||
#[allow(bad_style)]
|
|
||||||
#vis struct #name {
|
|
||||||
obj: ::wasm_bindgen::JsValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::wasm_bindgen::convert::WasmBoundary for #name {
|
|
||||||
type Js = <::wasm_bindgen::JsValue as
|
|
||||||
::wasm_bindgen::convert::WasmBoundary>::Js;
|
|
||||||
const DESCRIPTOR: u32 = <::wasm_bindgen::JsValue as
|
|
||||||
::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR;
|
|
||||||
|
|
||||||
fn into_js(self) -> Self::Js {
|
|
||||||
self.obj.into_js()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_js(js: Self::Js) -> Self {
|
|
||||||
#name { obj: ::wasm_bindgen::JsValue::from_js(js) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::wasm_bindgen::convert::ToRefWasmBoundary for #name {
|
|
||||||
fn to_js_ref(&self) -> u32 {
|
|
||||||
self.obj.to_js_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
fn from(obj: ::wasm_bindgen::JsValue) -> #name {
|
|
||||||
#name { obj }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<#name> for ::wasm_bindgen::JsValue {
|
|
||||||
fn from(obj: #name) -> ::wasm_bindgen::JsValue {
|
|
||||||
obj.obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).to_tokens(tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for ast::ImportKind {
|
|
||||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
|
||||||
match *self {
|
|
||||||
ast::ImportKind::Function(ref f) => f.to_tokens(tokens),
|
|
||||||
ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
|
|
||||||
ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for ast::ImportFunction {
|
|
||||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
|
||||||
let mut class_ty = None;
|
|
||||||
let mut is_method = false;
|
|
||||||
match self.kind {
|
|
||||||
ast::ImportFunctionKind::Method { ref ty, .. } => {
|
|
||||||
is_method = true;
|
|
||||||
class_ty = Some(ty);
|
|
||||||
}
|
|
||||||
ast::ImportFunctionKind::JsConstructor { ref ty, .. } => {
|
|
||||||
class_ty = Some(ty);
|
|
||||||
}
|
|
||||||
ast::ImportFunctionKind::Normal => {}
|
|
||||||
}
|
|
||||||
let vis = &self.function.rust_vis;
|
|
||||||
let ret = &self.function.rust_decl.output;
|
|
||||||
let fn_token = &self.function.rust_decl.fn_token;
|
|
||||||
|
|
||||||
let mut abi_argument_names = Vec::new();
|
|
||||||
let mut abi_arguments = Vec::new();
|
|
||||||
let mut arg_conversions = Vec::new();
|
|
||||||
let ret_ident = syn::Ident::from("_ret");
|
|
||||||
|
|
||||||
let names = self.function.rust_decl.inputs
|
|
||||||
.iter()
|
|
||||||
.map(|arg| {
|
|
||||||
match *arg {
|
|
||||||
syn::FnArg::Captured(ref c) => c,
|
|
||||||
_ => panic!("arguments cannot be `self` or ignored"),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|arg| {
|
|
||||||
match arg.pat {
|
|
||||||
syn::Pat::Ident(syn::PatIdent {
|
|
||||||
by_ref: None,
|
|
||||||
ident,
|
|
||||||
subpat: None,
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
ident
|
|
||||||
}
|
|
||||||
_ => panic!("unsupported pattern in foreign function"),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (i, (ty, name)) in self.function.arguments.iter().zip(names).enumerate() {
|
|
||||||
match *ty {
|
|
||||||
ast::Type::Vector(ref ty, owned) => {
|
|
||||||
let ptr = syn::Ident::from(format!("{}_ptr", name));
|
|
||||||
let len = syn::Ident::from(format!("{}_len", name));
|
|
||||||
abi_argument_names.push(ptr);
|
|
||||||
abi_argument_names.push(len);
|
|
||||||
let abi_ty = ty.abi_element();
|
|
||||||
abi_arguments.push(my_quote! { #ptr: *const #abi_ty });
|
|
||||||
abi_arguments.push(my_quote! { #len: usize });
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #ptr = #name.as_ptr();
|
|
||||||
let #len = #name.len();
|
|
||||||
});
|
|
||||||
if owned {
|
|
||||||
arg_conversions.push(my_quote! { ::std::mem::forget(#name); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::Type::ByValue(ref t) => {
|
|
||||||
abi_argument_names.push(name);
|
|
||||||
abi_arguments.push(my_quote! {
|
|
||||||
#name: <#t as ::wasm_bindgen::convert::WasmBoundary>::Js
|
|
||||||
});
|
|
||||||
if i == 0 && is_method {
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #name = <#t as ::wasm_bindgen::convert::WasmBoundary>
|
|
||||||
::into_js(self);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #name = <#t as ::wasm_bindgen::convert::WasmBoundary>
|
|
||||||
::into_js(#name);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::Type::ByMutRef(_) => panic!("urgh mut"),
|
|
||||||
ast::Type::ByRef(ref t) => {
|
|
||||||
abi_argument_names.push(name);
|
|
||||||
abi_arguments.push(my_quote! { #name: u32 });
|
|
||||||
if i == 0 && is_method {
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #name = <#t as ::wasm_bindgen::convert::ToRefWasmBoundary>
|
|
||||||
::to_js_ref(self);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let #name = <#t as ::wasm_bindgen::convert::ToRefWasmBoundary>
|
|
||||||
::to_js_ref(#name);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let abi_ret;
|
|
||||||
let mut convert_ret;
|
|
||||||
match self.function.ret {
|
|
||||||
Some(ast::Type::ByValue(ref t)) => {
|
|
||||||
abi_ret = my_quote! {
|
|
||||||
<#t as ::wasm_bindgen::convert::WasmBoundary>::Js
|
|
||||||
};
|
|
||||||
convert_ret = my_quote! {
|
|
||||||
<#t as ::wasm_bindgen::convert::WasmBoundary>::from_js(#ret_ident)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(ast::Type::Vector(ref ty, true)) => {
|
|
||||||
let name = syn::Ident::from("__ret_len");
|
|
||||||
let name_ptr = syn::Ident::from("__ret_len_ptr");
|
|
||||||
abi_argument_names.push(name_ptr);
|
|
||||||
abi_arguments.push(my_quote! { #name_ptr: *mut usize });
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let mut #name = 0;
|
|
||||||
let mut #name_ptr = &mut #name as *mut usize;
|
|
||||||
});
|
|
||||||
let abi_ty = ty.abi_element();
|
|
||||||
abi_ret = my_quote! { *mut #abi_ty };
|
|
||||||
if let ast::VectorType::String = *ty {
|
|
||||||
convert_ret = my_quote! {
|
|
||||||
String::from_utf8_unchecked(
|
|
||||||
Vec::from_raw_parts(#ret_ident, #name, #name)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
convert_ret = my_quote! {
|
|
||||||
Vec::from_raw_parts(#ret_ident, #name, #name)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(ast::Type::ByRef(_)) |
|
|
||||||
Some(ast::Type::Vector(_, false)) |
|
|
||||||
Some(ast::Type::ByMutRef(_)) => panic!("can't return a borrowed ref"),
|
|
||||||
None => {
|
|
||||||
abi_ret = my_quote! { () };
|
|
||||||
convert_ret = my_quote! { () };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut exceptional_ret = my_quote! {};
|
|
||||||
if self.function.opts.catch() {
|
|
||||||
let exn_data = syn::Ident::from("exn_data");
|
|
||||||
let exn_data_ptr = syn::Ident::from("exn_data_ptr");
|
|
||||||
abi_argument_names.push(exn_data_ptr);
|
|
||||||
abi_arguments.push(my_quote! { #exn_data_ptr: *mut u32 });
|
|
||||||
arg_conversions.push(my_quote! {
|
|
||||||
let mut #exn_data = [0; 2];
|
|
||||||
let #exn_data_ptr = #exn_data.as_mut_ptr();
|
|
||||||
});
|
|
||||||
convert_ret = my_quote! { Ok(#convert_ret) };
|
|
||||||
exceptional_ret = my_quote! {
|
|
||||||
if #exn_data[0] == 1 {
|
|
||||||
return Err(<::wasm_bindgen::JsValue as
|
|
||||||
::wasm_bindgen::convert::WasmBoundary>::from_js(#exn_data[1]))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let rust_name = self.rust_name;
|
|
||||||
let import_name = self.shim;
|
|
||||||
let attrs = &self.function.rust_attrs;
|
|
||||||
|
|
||||||
let arguments = self.function.rust_decl.inputs
|
|
||||||
.iter()
|
|
||||||
.skip(if is_method { 1 } else { 0 })
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let me = if is_method {
|
|
||||||
my_quote! { &self, }
|
|
||||||
} else {
|
|
||||||
quote!()
|
|
||||||
};
|
|
||||||
|
|
||||||
let invocation = my_quote! {
|
|
||||||
#(#attrs)*
|
|
||||||
#[allow(bad_style)]
|
|
||||||
#vis extern #fn_token #rust_name(#me #(#arguments),*) #ret {
|
|
||||||
::wasm_bindgen::__rt::link_this_library();
|
|
||||||
#[wasm_import_module = "__wbindgen_placeholder__"]
|
|
||||||
extern {
|
|
||||||
fn #import_name(#(#abi_arguments),*) -> #abi_ret;
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
#(#arg_conversions)*
|
|
||||||
let #ret_ident = #import_name(#(#abi_argument_names),*);
|
|
||||||
#exceptional_ret
|
|
||||||
#convert_ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(class) = class_ty {
|
|
||||||
(quote! {
|
|
||||||
impl #class {
|
|
||||||
#invocation
|
|
||||||
}
|
|
||||||
}).to_tokens(tokens);
|
|
||||||
} else {
|
|
||||||
invocation.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for ast::Enum {
|
|
||||||
fn to_tokens(&self, into: &mut Tokens) {
|
|
||||||
let enum_name = &self.name;
|
|
||||||
let c = shared::TYPE_ENUM as u32;
|
|
||||||
let incoming_u32 = quote! { n };
|
|
||||||
let enum_name_as_string = enum_name.to_string();
|
|
||||||
let cast_clauses = self.variants.iter().map(|variant| {
|
|
||||||
let variant_name = &variant.name;
|
|
||||||
quote! {
|
|
||||||
if #incoming_u32 == #enum_name::#variant_name as u32 {
|
|
||||||
#enum_name::#variant_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
(my_quote! {
|
|
||||||
impl #enum_name {
|
|
||||||
fn from_u32(#incoming_u32: u32) -> #enum_name {
|
|
||||||
#(#cast_clauses else)* {
|
|
||||||
wasm_bindgen::throw(&format!("Could not cast {} as {}", #incoming_u32, #enum_name_as_string));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::wasm_bindgen::convert::WasmBoundary for #enum_name {
|
|
||||||
type Js = u32;
|
|
||||||
const DESCRIPTOR: u32 = #c;
|
|
||||||
|
|
||||||
fn into_js(self) -> u32 {
|
|
||||||
self as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_js(js: u32) -> Self {
|
|
||||||
#enum_name::from_u32(js)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).to_tokens(into);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for ast::ImportStatic {
|
|
||||||
fn to_tokens(&self, into: &mut Tokens) {
|
|
||||||
let name = self.rust_name;
|
|
||||||
let ty = &self.ty;
|
|
||||||
let shim_name = self.shim;
|
|
||||||
let vis = &self.vis;
|
|
||||||
(my_quote! {
|
|
||||||
#[allow(bad_style)]
|
|
||||||
#vis static #name: ::wasm_bindgen::JsStatic<#ty> = {
|
|
||||||
fn init() -> #ty {
|
|
||||||
#[wasm_import_module = "__wbindgen_placeholder__"]
|
|
||||||
extern {
|
|
||||||
fn #shim_name() -> u32;
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
::wasm_bindgen::convert::WasmBoundary::from_js(#shim_name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
::wasm_bindgen::JsStatic {
|
|
||||||
__inner: ::std::cell::UnsafeCell::new(None),
|
|
||||||
__init: init,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}).to_tokens(into);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user