mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-21 00:36:33 +00:00
Greatly simplify handling of types in Rust
Push the compiler to do trait resolution to figure out what each type is bound with in JS, and that way we can accept effectively all types (so long as they implement a trait).
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
use proc_macro2::Span;
|
||||
use quote::{Tokens, ToTokens};
|
||||
use shared;
|
||||
use syn;
|
||||
use wasm_bindgen_shared as shared;
|
||||
|
||||
pub struct Program {
|
||||
pub structs: Vec<Struct>,
|
||||
@ -35,17 +36,13 @@ pub struct ImportStruct {
|
||||
}
|
||||
|
||||
pub enum Type {
|
||||
Integer(syn::Ident),
|
||||
// special
|
||||
BorrowedStr,
|
||||
String,
|
||||
ByValue(syn::Ident),
|
||||
ByRef(syn::Ident),
|
||||
ByMutRef(syn::Ident),
|
||||
RawMutPtr(syn::Ident),
|
||||
RawConstPtr(syn::Ident),
|
||||
JsObject,
|
||||
JsObjectRef,
|
||||
Boolean,
|
||||
|
||||
ByRef(syn::Type),
|
||||
ByMutRef(syn::Type),
|
||||
ByValue(syn::Type),
|
||||
}
|
||||
|
||||
pub struct Struct {
|
||||
@ -73,8 +70,13 @@ impl Program {
|
||||
if item.generics.params.len() > 0 {
|
||||
panic!("generic impls aren't supported");
|
||||
}
|
||||
let name = match Type::from(&item.self_ty) {
|
||||
Type::ByValue(ident) => ident,
|
||||
let name = match *item.self_ty {
|
||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
||||
match extract_path_ident(path) {
|
||||
Some(ident) => ident,
|
||||
None => panic!("unsupported self type in impl"),
|
||||
}
|
||||
}
|
||||
_ => panic!("unsupported self type in impl"),
|
||||
};
|
||||
let dst = self.structs
|
||||
@ -162,17 +164,20 @@ impl Program {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn shared(&self) -> shared::Program {
|
||||
shared::Program {
|
||||
structs: self.structs.iter().map(|s| s.shared()).collect(),
|
||||
free_functions: self.free_functions.iter().map(|s| s.shared()).collect(),
|
||||
imports: self.imports.iter()
|
||||
.map(|i| (i.module.clone(), i.function.wasm_function.shared()))
|
||||
.collect(),
|
||||
imported_structs: self.imported_structs.iter()
|
||||
.map(|i| i.shared())
|
||||
.collect(),
|
||||
}
|
||||
pub fn wbg_literal(&self, dst: &mut Tokens) -> usize {
|
||||
let mut a = LiteralBuilder {
|
||||
dst,
|
||||
cnt: 0,
|
||||
};
|
||||
a.append("wbg:");
|
||||
a.fields(&[
|
||||
("structs", &|a| a.list(&self.structs, Struct::wbg_literal)),
|
||||
("free_functions", &|a| a.list(&self.free_functions, Function::wbg_literal)),
|
||||
("imports", &|a| a.list(&self.imports, Import::wbg_literal)),
|
||||
("imported_structs", &|a| a.list(&self.imported_structs, ImportStruct::wbg_literal)),
|
||||
("custom_type_names", &|a| a.list(&self.structs, |s, a| a.str(s.name.as_ref()))),
|
||||
]);
|
||||
return a.cnt
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,12 +241,15 @@ impl Function {
|
||||
}
|
||||
|
||||
pub fn free_function_export_name(&self) -> syn::LitStr {
|
||||
let name = self.shared().free_function_export_name();
|
||||
let name = shared::free_function_export_name(self.name.as_ref());
|
||||
syn::LitStr::new(&name, Span::def_site())
|
||||
}
|
||||
|
||||
pub fn struct_function_export_name(&self, s: syn::Ident) -> syn::LitStr {
|
||||
let name = self.shared().struct_function_export_name(s.as_ref());
|
||||
let name = shared::struct_function_export_name(
|
||||
s.as_ref(),
|
||||
self.name.as_ref(),
|
||||
);
|
||||
syn::LitStr::new(&name, Span::def_site())
|
||||
}
|
||||
|
||||
@ -256,110 +264,83 @@ impl Function {
|
||||
syn::Ident::from(generated_name)
|
||||
}
|
||||
|
||||
pub fn shared(&self) -> shared::Function {
|
||||
shared::Function {
|
||||
name: self.name.as_ref().to_string(),
|
||||
arguments: self.arguments.iter().map(|t| t.shared()).collect(),
|
||||
ret: self.ret.as_ref().map(|t| t.shared()),
|
||||
}
|
||||
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
||||
a.fields(&[
|
||||
("name", &|a| a.str(self.name.as_ref())),
|
||||
("arguments", &|a| a.list(&self.arguments, Type::wbg_literal)),
|
||||
("ret", &|a| {
|
||||
match self.ret {
|
||||
Some(ref s) => s.wbg_literal(a),
|
||||
None => a.append("null"),
|
||||
}
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_path_ident(path: &syn::Path) -> syn::Ident {
|
||||
pub fn extract_path_ident(path: &syn::Path) -> Option<syn::Ident> {
|
||||
if path.leading_colon.is_some() {
|
||||
panic!("unsupported leading colon in path")
|
||||
return None
|
||||
}
|
||||
if path.segments.len() != 1 {
|
||||
panic!("unsupported path that needs name resolution")
|
||||
return None
|
||||
}
|
||||
match path.segments.first().unwrap().value().arguments {
|
||||
syn::PathArguments::None => {}
|
||||
_ => panic!("unsupported path that has path arguments")
|
||||
_ => return None,
|
||||
}
|
||||
path.segments.first().unwrap().value().ident
|
||||
path.segments.first().map(|v| v.value().ident)
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn from(ty: &syn::Type) -> Type {
|
||||
match *ty {
|
||||
syn::Type::Reference(ref r) => {
|
||||
if r.lifetime.is_some() {
|
||||
panic!("can't have lifetimes on references yet");
|
||||
}
|
||||
let mutable = r.mutability.is_some();
|
||||
match *r.elem {
|
||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
||||
let ident = extract_path_ident(path);
|
||||
match ident.as_ref() {
|
||||
"str" => {
|
||||
if mutable {
|
||||
panic!("mutable strings not allowed");
|
||||
}
|
||||
Type::BorrowedStr
|
||||
}
|
||||
"JsObject" if !mutable => Type::JsObjectRef,
|
||||
"JsObject" if mutable => {
|
||||
panic!("can't have mutable js object refs")
|
||||
}
|
||||
_ if mutable => Type::ByMutRef(ident),
|
||||
_ => Type::ByRef(ident),
|
||||
match ident.as_ref().map(|s| s.as_ref()) {
|
||||
Some("str") => return Type::BorrowedStr,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => panic!("unsupported reference type"),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
syn::Type::Ptr(ref p) => {
|
||||
let mutable = p.const_token.is_none();
|
||||
let ident = match *p.elem {
|
||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
||||
extract_path_ident(path)
|
||||
}
|
||||
_ => panic!("unsupported reference type"),
|
||||
};
|
||||
if mutable {
|
||||
Type::RawMutPtr(ident)
|
||||
return if r.mutability.is_some() {
|
||||
Type::ByMutRef((*r.elem).clone())
|
||||
} else {
|
||||
Type::RawConstPtr(ident)
|
||||
Type::ByRef((*r.elem).clone())
|
||||
}
|
||||
}
|
||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
||||
let ident = extract_path_ident(path);
|
||||
match ident.as_ref() {
|
||||
"i8" |
|
||||
"u8" |
|
||||
"u16" |
|
||||
"i16" |
|
||||
"u32" |
|
||||
"i32" |
|
||||
"isize" |
|
||||
"usize" |
|
||||
"f32" |
|
||||
"f64" => {
|
||||
Type::Integer(ident)
|
||||
}
|
||||
"bool" => Type::Boolean,
|
||||
"String" => Type::String,
|
||||
"JsObject" => Type::JsObject,
|
||||
_ => Type::ByValue(ident),
|
||||
match ident.as_ref().map(|s| s.as_ref()) {
|
||||
Some("String") => return Type::String,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => panic!("unsupported type"),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Type::ByValue(ty.clone())
|
||||
}
|
||||
|
||||
fn shared(&self) -> shared::Type {
|
||||
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
||||
match *self {
|
||||
Type::Integer(_) |
|
||||
Type::RawConstPtr(_) |
|
||||
Type::RawMutPtr(_) => shared::Type::Number,
|
||||
Type::BorrowedStr => shared::Type::BorrowedStr,
|
||||
Type::String => shared::Type::String,
|
||||
Type::ByValue(n) => shared::Type::ByValue(n.to_string()),
|
||||
Type::ByRef(n) => shared::Type::ByRef(n.to_string()),
|
||||
Type::ByMutRef(n) => shared::Type::ByMutRef(n.to_string()),
|
||||
Type::JsObject => shared::Type::JsObject,
|
||||
Type::JsObjectRef => shared::Type::JsObjectRef,
|
||||
Type::Boolean => shared::Type::Boolean,
|
||||
Type::BorrowedStr => a.char(shared::TYPE_BORROWED_STR),
|
||||
Type::String => a.char(shared::TYPE_STRING),
|
||||
Type::ByValue(ref t) => {
|
||||
a.as_char(my_quote! {
|
||||
<#t as ::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR as u8
|
||||
});
|
||||
}
|
||||
Type::ByRef(ref ty) |
|
||||
Type::ByMutRef(ref ty) => {
|
||||
a.as_char(my_quote! {
|
||||
((<#ty as ::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR as u32) |
|
||||
::wasm_bindgen::convert::DESCRIPTOR_CUSTOM_REF_FLAG) as u8
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -374,7 +355,7 @@ impl Struct {
|
||||
}
|
||||
|
||||
pub fn free_function(&self) -> syn::Ident {
|
||||
syn::Ident::from(self.shared().free_function())
|
||||
syn::Ident::from(shared::free_function(self.name.as_ref()))
|
||||
}
|
||||
|
||||
pub fn push_item(&mut self, item: &syn::ImplItem) {
|
||||
@ -412,33 +393,53 @@ impl Struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shared(&self) -> shared::Struct {
|
||||
shared::Struct {
|
||||
name: self.name.to_string(),
|
||||
functions: self.functions.iter().map(|f| f.shared()).collect(),
|
||||
methods: self.methods.iter().map(|f| f.shared()).collect(),
|
||||
}
|
||||
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
||||
a.fields(&[
|
||||
("name", &|a| a.str(self.name.as_ref())),
|
||||
("functions", &|a| a.list(&self.functions, Function::wbg_literal)),
|
||||
("methods", &|a| a.list(&self.methods, Method::wbg_literal)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
impl Method {
|
||||
pub fn shared(&self) -> shared::Method {
|
||||
shared::Method {
|
||||
mutable: self.mutable,
|
||||
function: self.function.shared(),
|
||||
}
|
||||
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
||||
a.fields(&[
|
||||
("mutable", &|a| a.bool(self.mutable)),
|
||||
("function", &|a| self.function.wbg_literal(a)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
||||
a.fields(&[
|
||||
("module", &|a| {
|
||||
match self.module {
|
||||
Some(ref s) => a.str(s),
|
||||
None => a.append("null"),
|
||||
}
|
||||
}),
|
||||
("name", &|a| a.str(self.name.as_ref())),
|
||||
("functions", &|a| {
|
||||
a.list(&self.functions,
|
||||
|&(is_method, ref f), a| {
|
||||
a.fields(&[
|
||||
("method", &|a| a.bool(is_method)),
|
||||
("function", &|a| f.wasm_function.wbg_literal(a)),
|
||||
]);
|
||||
})
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
impl Import {
|
||||
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
||||
a.fields(&[
|
||||
("module", &|a| a.str(&self.module)),
|
||||
("function", &|a| self.function.wasm_function.wbg_literal(a)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -503,3 +504,91 @@ fn term<'a>(cursor: syn::buffer::Cursor<'a>, name: &str)
|
||||
}
|
||||
syn::parse_error()
|
||||
}
|
||||
|
||||
struct LiteralBuilder<'a> {
|
||||
dst: &'a mut Tokens,
|
||||
cnt: usize,
|
||||
}
|
||||
|
||||
impl<'a> LiteralBuilder<'a> {
|
||||
fn byte(&mut self, byte: u8) {
|
||||
if self.cnt > 0 {
|
||||
::syn::token::Comma::default().to_tokens(self.dst);
|
||||
}
|
||||
self.cnt += 1;
|
||||
byte.to_tokens(self.dst);
|
||||
}
|
||||
|
||||
fn append(&mut self, s: &str) {
|
||||
for byte in s.bytes() {
|
||||
self.byte(byte);
|
||||
}
|
||||
}
|
||||
|
||||
fn str(&mut self, s: &str) {
|
||||
self.append("\"");
|
||||
self.append(s);
|
||||
self.append("\"");
|
||||
}
|
||||
|
||||
fn bool(&mut self, v: bool) {
|
||||
if v {
|
||||
self.append("true")
|
||||
} else {
|
||||
self.append("false")
|
||||
}
|
||||
}
|
||||
|
||||
fn char(&mut self, s: char) {
|
||||
self.append("\"\\u");
|
||||
let s = s as u32;
|
||||
self.byte(to_hex((s >> 12) as u8));
|
||||
self.byte(to_hex((s >> 8) as u8));
|
||||
self.byte(to_hex((s >> 4) as u8));
|
||||
self.byte(to_hex((s >> 0) as u8));
|
||||
self.append("\"");
|
||||
|
||||
fn to_hex(a: u8) -> u8 {
|
||||
let a = a & 0xf;
|
||||
match a {
|
||||
0 ... 9 => b'0' + a,
|
||||
_ => b'a'+ a - 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn as_char(&mut self, tokens: Tokens) {
|
||||
self.append("\"");
|
||||
::syn::token::Comma::default().to_tokens(self.dst);
|
||||
tokens.to_tokens(self.dst);
|
||||
self.cnt += 1;
|
||||
self.append("\"");
|
||||
}
|
||||
|
||||
fn fields(&mut self, fields: &[(&str, &Fn(&mut Self))]) {
|
||||
self.append("{");
|
||||
for (i, &(field, cb)) in fields.iter().enumerate() {
|
||||
if i > 0 {
|
||||
self.append(",");
|
||||
}
|
||||
self.str(field);
|
||||
self.append(":");
|
||||
cb(self);
|
||||
}
|
||||
self.append("}");
|
||||
}
|
||||
|
||||
fn list<T, F>(&mut self, list: T, mut cb: F)
|
||||
where F: FnMut(T::Item, &mut Self),
|
||||
T: IntoIterator,
|
||||
{
|
||||
self.append("[");
|
||||
for (i, element) in list.into_iter().enumerate() {
|
||||
if i > 0 {
|
||||
self.append(",");
|
||||
}
|
||||
cb(element, self);
|
||||
}
|
||||
self.append("]");
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#![recursion_limit = "128"]
|
||||
#![feature(proc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
@ -7,23 +8,24 @@ extern crate quote;
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
extern crate serde_json;
|
||||
extern crate wasm_bindgen_shared;
|
||||
extern crate wasm_bindgen_shared as shared;
|
||||
|
||||
use std::char;
|
||||
use std::sync::atomic::*;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Span, TokenNode, Delimiter, TokenTree};
|
||||
use quote::{Tokens, ToTokens};
|
||||
|
||||
macro_rules! my_quote {
|
||||
($($t:tt)*) => (quote_spanned!(Span::call_site() => $($t)*))
|
||||
}
|
||||
|
||||
mod ast;
|
||||
|
||||
static MALLOC_GENERATED: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
static BOXED_STR_GENERATED: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
macro_rules! my_quote {
|
||||
($($t:tt)*) => (quote_spanned!(Span::call_site() => $($t)*))
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
||||
// Parse the input as a list of Rust items, reusing the `syn::File` parser.
|
||||
@ -80,8 +82,8 @@ pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
||||
for function in program.free_functions.iter() {
|
||||
bindgen_fn(function, &mut ret);
|
||||
}
|
||||
for s in program.structs.iter() {
|
||||
bindgen_struct(s, &mut ret);
|
||||
for (i, s) in program.structs.iter().enumerate() {
|
||||
bindgen_struct(i, s, &mut ret);
|
||||
}
|
||||
for i in program.imports.iter() {
|
||||
bindgen_import(i, &mut ret);
|
||||
@ -98,19 +100,14 @@ pub fn wasm_bindgen(input: TokenStream) -> TokenStream {
|
||||
let generated_static_name = format!("__WASM_BINDGEN_GENERATED{}",
|
||||
CNT.fetch_add(1, Ordering::SeqCst));
|
||||
let generated_static_name = syn::Ident::from(generated_static_name);
|
||||
let mut generated_static = String::from("wbg:");
|
||||
generated_static.push_str(&serde_json::to_string(&program.shared()).unwrap());
|
||||
let generated_static_value = syn::LitByteStr::new(
|
||||
generated_static.as_bytes(),
|
||||
Span::def_site(),
|
||||
);
|
||||
let generated_static_length = generated_static.len();
|
||||
let mut generated_static_value = Tokens::new();
|
||||
let generated_static_length = program.wbg_literal(&mut generated_static_value);
|
||||
|
||||
(my_quote! {
|
||||
#[no_mangle]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub static #generated_static_name: [u8; #generated_static_length] =
|
||||
*#generated_static_value;
|
||||
[#generated_static_value];
|
||||
}).to_tokens(&mut ret);
|
||||
|
||||
// println!("{}", ret);
|
||||
@ -127,7 +124,7 @@ fn bindgen_fn(function: &ast::Function, into: &mut Tokens) {
|
||||
into)
|
||||
}
|
||||
|
||||
fn bindgen_struct(s: &ast::Struct, into: &mut Tokens) {
|
||||
fn bindgen_struct(idx: usize, s: &ast::Struct, into: &mut Tokens) {
|
||||
for f in s.functions.iter() {
|
||||
bindgen_struct_fn(s, f, into);
|
||||
}
|
||||
@ -137,11 +134,47 @@ fn bindgen_struct(s: &ast::Struct, into: &mut Tokens) {
|
||||
|
||||
let name = &s.name;
|
||||
let free_fn = s.free_function();
|
||||
let c = char::from_u32(idx as u32 * 2 + shared::TYPE_CUSTOM_START);
|
||||
(my_quote! {
|
||||
impl ::wasm_bindgen::convert::WasmBoundary for #name {
|
||||
type Js = u32;
|
||||
const DESCRIPTOR: char = #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: *mut ::wasm_bindgen::__rt::WasmRefCell<#name>) {
|
||||
::wasm_bindgen::__rt::assert_not_null(ptr);
|
||||
drop(Box::from_raw(ptr));
|
||||
pub unsafe extern fn #free_fn(ptr: u32) {
|
||||
<#name as ::wasm_bindgen::convert::WasmBoundary>::from_js(ptr);
|
||||
}
|
||||
}).to_tokens(into);
|
||||
}
|
||||
@ -198,21 +231,6 @@ fn bindgen(export_name: &syn::LitStr,
|
||||
let i = i + offset;
|
||||
let ident = syn::Ident::from(format!("arg{}", i));
|
||||
match *ty {
|
||||
ast::Type::Integer(i) => {
|
||||
args.push(my_quote! { #ident: #i });
|
||||
}
|
||||
ast::Type::Boolean => {
|
||||
args.push(my_quote! { #ident: u32 });
|
||||
arg_conversions.push(my_quote! {
|
||||
let #ident = #ident != 0;
|
||||
});
|
||||
}
|
||||
ast::Type::RawMutPtr(i) => {
|
||||
args.push(my_quote! { #ident: *mut #i });
|
||||
}
|
||||
ast::Type::RawConstPtr(i) => {
|
||||
args.push(my_quote! { #ident: *const #i });
|
||||
}
|
||||
ast::Type::BorrowedStr => {
|
||||
malloc = malloc || !MALLOC_GENERATED.swap(true, Ordering::SeqCst);
|
||||
let ptr = syn::Ident::from(format!("arg{}_ptr", i));
|
||||
@ -239,90 +257,63 @@ fn bindgen(export_name: &syn::LitStr,
|
||||
};
|
||||
});
|
||||
}
|
||||
ast::Type::ByValue(name) => {
|
||||
args.push(my_quote! { #ident: *mut ::wasm_bindgen::__rt::WasmRefCell<#name> });
|
||||
ast::Type::ByValue(ref t) => {
|
||||
args.push(my_quote! {
|
||||
#ident: <#t as ::wasm_bindgen::convert::WasmBoundary >::Js
|
||||
});
|
||||
arg_conversions.push(my_quote! {
|
||||
::wasm_bindgen::__rt::assert_not_null(#ident);
|
||||
let #ident = unsafe {
|
||||
(*#ident).borrow_mut();
|
||||
Box::from_raw(#ident).into_inner()
|
||||
<#t as ::wasm_bindgen::convert::WasmBoundary>
|
||||
::from_js(#ident)
|
||||
};
|
||||
});
|
||||
}
|
||||
ast::Type::ByRef(name) => {
|
||||
args.push(my_quote! { #ident: *mut ::wasm_bindgen::__rt::WasmRefCell<#name> });
|
||||
ast::Type::ByRef(ref ty) => {
|
||||
args.push(my_quote! {
|
||||
#ident: <#ty as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||
});
|
||||
arg_conversions.push(my_quote! {
|
||||
::wasm_bindgen::__rt::assert_not_null(#ident);
|
||||
let #ident = unsafe { (*#ident).borrow() };
|
||||
let #ident = unsafe {
|
||||
<#ty as ::wasm_bindgen::convert::FromRefWasmBoundary>
|
||||
::from_js_ref(#ident)
|
||||
};
|
||||
let #ident = &*#ident;
|
||||
});
|
||||
}
|
||||
ast::Type::ByMutRef(name) => {
|
||||
args.push(my_quote! { #ident: *mut ::wasm_bindgen::__rt::WasmRefCell<#name> });
|
||||
ast::Type::ByMutRef(ref ty) => {
|
||||
args.push(my_quote! {
|
||||
#ident: <#ty as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||
});
|
||||
arg_conversions.push(my_quote! {
|
||||
::wasm_bindgen::__rt::assert_not_null(#ident);
|
||||
let mut #ident = unsafe { (*#ident).borrow_mut() };
|
||||
let mut #ident = unsafe {
|
||||
<#ty as ::wasm_bindgen::convert::FromRefMutWasmBoundary>
|
||||
::from_js_ref_mut(#ident)
|
||||
};
|
||||
let #ident = &mut *#ident;
|
||||
});
|
||||
}
|
||||
ast::Type::JsObject => {
|
||||
args.push(my_quote! { #ident: u32 });
|
||||
arg_conversions.push(my_quote! {
|
||||
let #ident = ::wasm_bindgen::JsObject::__from_idx(#ident);
|
||||
});
|
||||
}
|
||||
ast::Type::JsObjectRef => {
|
||||
args.push(my_quote! { #ident: u32 });
|
||||
arg_conversions.push(my_quote! {
|
||||
let #ident = ::std::mem::ManuallyDrop::new(
|
||||
::wasm_bindgen::JsObject::__from_idx(#ident)
|
||||
);
|
||||
let #ident = &*#ident;
|
||||
});
|
||||
}
|
||||
}
|
||||
converted_arguments.push(my_quote! { #ident });
|
||||
}
|
||||
let ret_ty;
|
||||
let convert_ret;
|
||||
match ret_type {
|
||||
Some(&ast::Type::Integer(i)) => {
|
||||
ret_ty = my_quote! { -> #i };
|
||||
convert_ret = my_quote! { #ret };
|
||||
}
|
||||
Some(&ast::Type::Boolean) => {
|
||||
ret_ty = my_quote! { -> u32 };
|
||||
convert_ret = my_quote! { #ret as u32 };
|
||||
}
|
||||
Some(&ast::Type::RawMutPtr(i)) => {
|
||||
ret_ty = my_quote! { -> *mut #i };
|
||||
convert_ret = my_quote! { #ret };
|
||||
}
|
||||
Some(&ast::Type::RawConstPtr(i)) => {
|
||||
ret_ty = my_quote! { -> *const #i };
|
||||
convert_ret = my_quote! { #ret };
|
||||
}
|
||||
Some(&ast::Type::BorrowedStr) => panic!("can't return a borrowed string"),
|
||||
Some(&ast::Type::ByRef(_)) => panic!("can't return a borrowed ref"),
|
||||
Some(&ast::Type::ByMutRef(_)) => panic!("can't return a borrowed ref"),
|
||||
Some(&ast::Type::String) => {
|
||||
boxed_str = !BOXED_STR_GENERATED.swap(true, Ordering::SeqCst);
|
||||
ret_ty = my_quote! { -> *mut String };
|
||||
convert_ret = my_quote! { Box::into_raw(Box::new(#ret)) };
|
||||
}
|
||||
Some(&ast::Type::ByValue(name)) => {
|
||||
ret_ty = my_quote! { -> *mut ::wasm_bindgen::__rt::WasmRefCell<#name> };
|
||||
Some(&ast::Type::ByValue(ref t)) => {
|
||||
ret_ty = my_quote! {
|
||||
-> <#t as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||
};
|
||||
convert_ret = my_quote! {
|
||||
Box::into_raw(Box::new(::wasm_bindgen::__rt::WasmRefCell::new(#ret)))
|
||||
<#t as ::wasm_bindgen::convert::WasmBoundary>::into_js(#ret)
|
||||
};
|
||||
}
|
||||
Some(&ast::Type::JsObject) => {
|
||||
ret_ty = my_quote! { -> u32 };
|
||||
convert_ret = my_quote! {
|
||||
::wasm_bindgen::JsObject::__into_idx(#ret)
|
||||
};
|
||||
}
|
||||
Some(&ast::Type::JsObjectRef) => {
|
||||
Some(&ast::Type::BorrowedStr) |
|
||||
Some(&ast::Type::ByMutRef(_)) |
|
||||
Some(&ast::Type::ByRef(_)) => {
|
||||
panic!("can't return a borrowed ref");
|
||||
}
|
||||
None => {
|
||||
@ -331,6 +322,8 @@ fn bindgen(export_name: &syn::LitStr,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move this function into wasm-bindgen-the-crate and then gc it out
|
||||
// if it's not used.
|
||||
let malloc = if malloc {
|
||||
my_quote! {
|
||||
#[no_mangle]
|
||||
@ -429,8 +422,10 @@ impl ToTokens for Receiver {
|
||||
}
|
||||
|
||||
fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
|
||||
let import_name = import.function.wasm_function.shared()
|
||||
.mangled_import_name(None);
|
||||
let import_name = shared::mangled_import_name(
|
||||
None,
|
||||
import.function.wasm_function.name.as_ref(),
|
||||
);
|
||||
bindgen_import_function(&import.function, &import_name, tokens);
|
||||
}
|
||||
|
||||
@ -445,8 +440,10 @@ fn bindgen_imported_struct(import: &ast::ImportStruct, tokens: &mut Tokens) {
|
||||
let mut methods = Tokens::new();
|
||||
|
||||
for &(_is_method, ref f) in import.functions.iter() {
|
||||
let import_name = f.wasm_function.shared()
|
||||
.mangled_import_name(Some(&import.name.to_string()));
|
||||
let import_name = shared::mangled_import_name(
|
||||
Some(&import.name.to_string()),
|
||||
f.wasm_function.name.as_ref(),
|
||||
);
|
||||
bindgen_import_function(f, &import_name, &mut methods);
|
||||
}
|
||||
|
||||
@ -494,26 +491,6 @@ fn bindgen_import_function(import: &ast::ImportFunction,
|
||||
|
||||
for (ty, name) in import.wasm_function.arguments.iter().zip(names) {
|
||||
match *ty {
|
||||
ast::Type::Integer(i) => {
|
||||
abi_argument_names.push(name);
|
||||
abi_arguments.push(my_quote! { #name: #i });
|
||||
arg_conversions.push(my_quote! {});
|
||||
}
|
||||
ast::Type::Boolean => {
|
||||
abi_argument_names.push(name);
|
||||
abi_arguments.push(my_quote! { #name: u32 });
|
||||
arg_conversions.push(my_quote! { let #name = #name as u32; });
|
||||
}
|
||||
ast::Type::RawMutPtr(i) => {
|
||||
abi_argument_names.push(name);
|
||||
abi_arguments.push(my_quote! { #name: *mut #i });
|
||||
arg_conversions.push(my_quote! {});
|
||||
}
|
||||
ast::Type::RawConstPtr(i) => {
|
||||
abi_argument_names.push(name);
|
||||
abi_arguments.push(my_quote! { #name: *const #i });
|
||||
arg_conversions.push(my_quote! {});
|
||||
}
|
||||
ast::Type::BorrowedStr => {
|
||||
let ptr = syn::Ident::from(format!("{}_ptr", name));
|
||||
let len = syn::Ident::from(format!("{}_len", name));
|
||||
@ -526,59 +503,70 @@ fn bindgen_import_function(import: &ast::ImportFunction,
|
||||
let #len = #name.len();
|
||||
});
|
||||
}
|
||||
ast::Type::JsObject => {
|
||||
ast::Type::ByValue(ref t) => {
|
||||
abi_argument_names.push(name);
|
||||
abi_arguments.push(my_quote! {
|
||||
#name: <#t as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||
});
|
||||
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 });
|
||||
arg_conversions.push(my_quote! {
|
||||
let #name = ::wasm_bindgen::JsObject::__into_idx(#name);
|
||||
let #name = <#t as ::wasm_bindgen::convert::ToRefWasmBoundary>
|
||||
::to_js_ref(#name);
|
||||
});
|
||||
}
|
||||
ast::Type::JsObjectRef => {
|
||||
abi_argument_names.push(name);
|
||||
abi_arguments.push(my_quote! { #name: u32 });
|
||||
// TODO: need to test this
|
||||
ast::Type::String => {
|
||||
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);
|
||||
abi_arguments.push(my_quote! { #ptr: *const u8 });
|
||||
abi_arguments.push(my_quote! { #len: usize });
|
||||
arg_conversions.push(my_quote! {
|
||||
let #name = ::wasm_bindgen::JsObject::__get_idx(#name);
|
||||
let #ptr = #name.as_ptr();
|
||||
let #len = #name.len();
|
||||
::std::mem::forget(#name);
|
||||
});
|
||||
}
|
||||
ast::Type::String => panic!("can't use `String` in foreign functions"),
|
||||
ast::Type::ByValue(_name) |
|
||||
ast::Type::ByRef(_name) |
|
||||
ast::Type::ByMutRef(_name) => {
|
||||
panic!("can't use struct types in foreign functions yet");
|
||||
}
|
||||
}
|
||||
}
|
||||
let abi_ret;
|
||||
let convert_ret;
|
||||
match import.wasm_function.ret {
|
||||
Some(ast::Type::Integer(i)) => {
|
||||
abi_ret = my_quote! { #i };
|
||||
convert_ret = my_quote! { #ret_ident };
|
||||
}
|
||||
Some(ast::Type::Boolean) => {
|
||||
abi_ret = my_quote! { u32 };
|
||||
convert_ret = my_quote! { #ret_ident != 0 };
|
||||
}
|
||||
Some(ast::Type::RawConstPtr(i)) => {
|
||||
abi_ret = my_quote! { *const #i };
|
||||
convert_ret = my_quote! { #ret_ident };
|
||||
}
|
||||
Some(ast::Type::RawMutPtr(i)) => {
|
||||
abi_ret = my_quote! { *mut #i };
|
||||
convert_ret = my_quote! { #ret_ident };
|
||||
}
|
||||
Some(ast::Type::JsObject) => {
|
||||
abi_ret = my_quote! { u32 };
|
||||
Some(ast::Type::ByValue(ref t)) => {
|
||||
abi_ret = my_quote! {
|
||||
<#t as ::wasm_bindgen::convert::WasmBoundary>::Js
|
||||
};
|
||||
convert_ret = my_quote! {
|
||||
::wasm_bindgen::JsObject::__from_idx(#ret_ident)
|
||||
<#t as ::wasm_bindgen::convert::WasmBoundary>::from_js(#ret_ident)
|
||||
};
|
||||
}
|
||||
Some(ast::Type::JsObjectRef) => panic!("can't return a borrowed ref"),
|
||||
Some(ast::Type::BorrowedStr) => panic!("can't return a borrowed string"),
|
||||
Some(ast::Type::ByRef(_)) => panic!("can't return a borrowed ref"),
|
||||
|
||||
// TODO: add a test for this
|
||||
Some(ast::Type::String) => {
|
||||
let name = syn::Ident::from("__ret_strlen");
|
||||
abi_argument_names.push(name);
|
||||
abi_arguments.push(my_quote! { #name: *mut usize });
|
||||
arg_conversions.push(my_quote! {
|
||||
let mut #name = 0;
|
||||
});
|
||||
abi_ret = my_quote! { *const u8 };
|
||||
convert_ret = my_quote! {
|
||||
let __v = Vec::from_raw_parts(#ret_ident, #name, #name);
|
||||
String::from_utf8_unchecked(__v)
|
||||
};
|
||||
}
|
||||
Some(ast::Type::BorrowedStr) |
|
||||
Some(ast::Type::ByRef(_)) |
|
||||
Some(ast::Type::ByMutRef(_)) => panic!("can't return a borrowed ref"),
|
||||
Some(ast::Type::String) => panic!("can't return a string in foreign functions"),
|
||||
Some(ast::Type::ByValue(_)) => panic!("can't return a struct in a foreign function"),
|
||||
None => {
|
||||
abi_ret = my_quote! { () };
|
||||
convert_ret = my_quote! {};
|
||||
|
Reference in New Issue
Block a user