mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-12 20:41:24 +00:00
@ -49,14 +49,25 @@ pub struct Struct {
|
||||
|
||||
pub enum Type {
|
||||
// special
|
||||
BorrowedStr,
|
||||
String,
|
||||
Vector(VectorType, bool),
|
||||
|
||||
ByRef(syn::Type),
|
||||
ByMutRef(syn::Type),
|
||||
ByValue(syn::Type),
|
||||
}
|
||||
|
||||
pub enum VectorType {
|
||||
String,
|
||||
I8,
|
||||
U8,
|
||||
I16,
|
||||
U16,
|
||||
I32,
|
||||
U32,
|
||||
F32,
|
||||
F64,
|
||||
}
|
||||
|
||||
impl Program {
|
||||
pub fn push_item(&mut self,
|
||||
item: syn::Item,
|
||||
@ -216,8 +227,8 @@ impl Program {
|
||||
Type::ByMutRef(_) => {
|
||||
panic!("first method argument cannot be mutable ref")
|
||||
}
|
||||
Type::String | Type::BorrowedStr => {
|
||||
panic!("method receivers cannot be strings")
|
||||
Type::Vector(..) => {
|
||||
panic!("method receivers cannot be vectors")
|
||||
}
|
||||
};
|
||||
let class_name = match *class {
|
||||
@ -422,10 +433,15 @@ impl Type {
|
||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
||||
let ident = extract_path_ident(path);
|
||||
match ident.as_ref().map(|s| s.as_ref()) {
|
||||
Some("str") => return Type::BorrowedStr,
|
||||
Some("str") => return Type::Vector(VectorType::String, false),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
syn::Type::Slice(ref slice) => {
|
||||
if let Some(ty) = VectorType::from(&slice.elem) {
|
||||
return Type::Vector(ty, false)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return if r.mutability.is_some() {
|
||||
@ -434,10 +450,29 @@ impl Type {
|
||||
Type::ByRef((*r.elem).clone())
|
||||
}
|
||||
}
|
||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => {
|
||||
let ident = extract_path_ident(path);
|
||||
match ident.as_ref().map(|s| s.as_ref()) {
|
||||
Some("String") => return Type::String,
|
||||
syn::Type::Path(syn::TypePath { qself: None, ref path })
|
||||
if path.leading_colon.is_none() && path.segments.len() == 1 =>
|
||||
{
|
||||
let seg = path.segments.first().unwrap().into_value();
|
||||
match seg.arguments {
|
||||
syn::PathArguments::None => {
|
||||
match seg.ident.as_ref() {
|
||||
"String" => return Type::Vector(VectorType::String, true),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
syn::PathArguments::AngleBracketed(ref t)
|
||||
if seg.ident == "Vec" && t.args.len() == 1 =>
|
||||
{
|
||||
match **t.args.first().unwrap().value() {
|
||||
syn::GenericArgument::Type(ref t) => {
|
||||
if let Some(ty) = VectorType::from(t) {
|
||||
return Type::Vector(ty, true)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -449,8 +484,24 @@ impl Type {
|
||||
|
||||
fn wbg_literal(&self, a: &mut LiteralBuilder) {
|
||||
match *self {
|
||||
Type::BorrowedStr => a.char(shared::TYPE_BORROWED_STR),
|
||||
Type::String => a.char(shared::TYPE_STRING),
|
||||
Type::Vector(VectorType::String, true) => a.char(shared::TYPE_STRING),
|
||||
Type::Vector(VectorType::String, false) => a.char(shared::TYPE_BORROWED_STR),
|
||||
Type::Vector(VectorType::U8, true) => a.char(shared::TYPE_VECTOR_U8),
|
||||
Type::Vector(VectorType::U8, false) => a.char(shared::TYPE_SLICE_U8),
|
||||
Type::Vector(VectorType::I8, true) => a.char(shared::TYPE_VECTOR_I8),
|
||||
Type::Vector(VectorType::I8, false) => a.char(shared::TYPE_SLICE_I8),
|
||||
Type::Vector(VectorType::U16, true) => a.char(shared::TYPE_VECTOR_U16),
|
||||
Type::Vector(VectorType::U16, false) => a.char(shared::TYPE_SLICE_U16),
|
||||
Type::Vector(VectorType::I16, true) => a.char(shared::TYPE_VECTOR_I16),
|
||||
Type::Vector(VectorType::I16, false) => a.char(shared::TYPE_SLICE_I16),
|
||||
Type::Vector(VectorType::U32, true) => a.char(shared::TYPE_VECTOR_U32),
|
||||
Type::Vector(VectorType::U32, false) => a.char(shared::TYPE_SLICE_U32),
|
||||
Type::Vector(VectorType::I32, true) => a.char(shared::TYPE_VECTOR_I32),
|
||||
Type::Vector(VectorType::I32, false) => a.char(shared::TYPE_SLICE_I32),
|
||||
Type::Vector(VectorType::F32, true) => a.char(shared::TYPE_VECTOR_F32),
|
||||
Type::Vector(VectorType::F32, false) => a.char(shared::TYPE_SLICE_F32),
|
||||
Type::Vector(VectorType::F64, true) => a.char(shared::TYPE_VECTOR_F64),
|
||||
Type::Vector(VectorType::F64, false) => a.char(shared::TYPE_SLICE_F64),
|
||||
Type::ByValue(ref t) => {
|
||||
a.as_char(my_quote! {
|
||||
<#t as ::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR
|
||||
@ -849,3 +900,61 @@ fn term<'a>(cursor: syn::buffer::Cursor<'a>, name: &str)
|
||||
}
|
||||
syn::parse_error()
|
||||
}
|
||||
|
||||
fn ungroup(input: &syn::Type) -> &syn::Type {
|
||||
match *input {
|
||||
syn::Type::Group(ref t) => &t.elem,
|
||||
_ => input,
|
||||
}
|
||||
}
|
||||
|
||||
impl VectorType {
|
||||
fn from(ty: &syn::Type) -> Option<VectorType> {
|
||||
let path = match *ungroup(ty) {
|
||||
syn::Type::Path(syn::TypePath { qself: None, ref path }) => path,
|
||||
_ => return None,
|
||||
};
|
||||
match extract_path_ident(path)?.as_ref() {
|
||||
"i8" => Some(VectorType::I8),
|
||||
"u8" => Some(VectorType::U8),
|
||||
"i16" => Some(VectorType::I16),
|
||||
"u16" => Some(VectorType::U16),
|
||||
"i32" => Some(VectorType::I32),
|
||||
"u32" => Some(VectorType::U32),
|
||||
"f32" => Some(VectorType::F32),
|
||||
"f64" => Some(VectorType::F64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn abi_element(&self) -> syn::Ident {
|
||||
match *self {
|
||||
VectorType::String => syn::Ident::from("u8"),
|
||||
VectorType::I8 => syn::Ident::from("i8"),
|
||||
VectorType::U8 => syn::Ident::from("u8"),
|
||||
VectorType::I16 => syn::Ident::from("i16"),
|
||||
VectorType::U16 => syn::Ident::from("u16"),
|
||||
VectorType::I32 => syn::Ident::from("i32"),
|
||||
VectorType::U32 => syn::Ident::from("u32"),
|
||||
VectorType::F32 => syn::Ident::from("f32"),
|
||||
VectorType::F64 => syn::Ident::from("f64"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for VectorType {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let me = match *self {
|
||||
VectorType::String => my_quote! { String },
|
||||
VectorType::I8 => my_quote! { Vec<i8> },
|
||||
VectorType::U8 => my_quote! { Vec<u8> },
|
||||
VectorType::I16 => my_quote! { Vec<i16> },
|
||||
VectorType::U16 => my_quote! { Vec<u16> },
|
||||
VectorType::I32 => my_quote! { Vec<i32> },
|
||||
VectorType::U32 => my_quote! { Vec<u32> },
|
||||
VectorType::F32 => my_quote! { Vec<f32> },
|
||||
VectorType::F64 => my_quote! { Vec<f64> },
|
||||
};
|
||||
me.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
@ -144,29 +144,40 @@ fn bindgen_export(export: &ast::Export, into: &mut Tokens) {
|
||||
let i = i + offset;
|
||||
let ident = syn::Ident::from(format!("arg{}", i));
|
||||
match *ty {
|
||||
ast::Type::BorrowedStr => {
|
||||
ast::Type::Vector(ref ty, owned) => {
|
||||
let ptr = syn::Ident::from(format!("arg{}_ptr", i));
|
||||
let len = syn::Ident::from(format!("arg{}_len", i));
|
||||
args.push(my_quote! { #ptr: *const u8 });
|
||||
let abi_ty = ty.abi_element();
|
||||
args.push(my_quote! { #ptr: *const #abi_ty });
|
||||
args.push(my_quote! { #len: usize });
|
||||
arg_conversions.push(my_quote! {
|
||||
let #ident = unsafe {
|
||||
let slice = ::std::slice::from_raw_parts(#ptr, #len);
|
||||
::std::str::from_utf8_unchecked(slice)
|
||||
};
|
||||
});
|
||||
}
|
||||
ast::Type::String => {
|
||||
let ptr = syn::Ident::from(format!("arg{}_ptr", i));
|
||||
let len = syn::Ident::from(format!("arg{}_len", i));
|
||||
args.push(my_quote! { #ptr: *mut u8 });
|
||||
args.push(my_quote! { #len: usize });
|
||||
arg_conversions.push(my_quote! {
|
||||
let #ident = unsafe {
|
||||
let vec = ::std::vec::Vec::from_raw_parts(#ptr, #len, #len);
|
||||
::std::string::String::from_utf8_unchecked(vec)
|
||||
};
|
||||
});
|
||||
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, #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! {
|
||||
@ -209,8 +220,8 @@ fn bindgen_export(export: &ast::Export, into: &mut Tokens) {
|
||||
let ret_ty;
|
||||
let convert_ret;
|
||||
match export.function.ret {
|
||||
Some(ast::Type::String) => {
|
||||
ret_ty = my_quote! { -> *mut String };
|
||||
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)) => {
|
||||
@ -221,7 +232,7 @@ fn bindgen_export(export: &ast::Export, into: &mut Tokens) {
|
||||
<#t as ::wasm_bindgen::convert::WasmBoundary>::into_js(#ret)
|
||||
};
|
||||
}
|
||||
Some(ast::Type::BorrowedStr) |
|
||||
Some(ast::Type::Vector(_, false)) |
|
||||
Some(ast::Type::ByMutRef(_)) |
|
||||
Some(ast::Type::ByRef(_)) => {
|
||||
panic!("can't return a borrowed ref");
|
||||
@ -344,17 +355,21 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
|
||||
|
||||
for (i, (ty, name)) in import.function.arguments.iter().zip(names).enumerate() {
|
||||
match *ty {
|
||||
ast::Type::BorrowedStr => {
|
||||
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);
|
||||
abi_arguments.push(my_quote! { #ptr: *const u8 });
|
||||
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);
|
||||
@ -389,20 +404,6 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
|
||||
});
|
||||
}
|
||||
}
|
||||
// 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 #ptr = #name.as_ptr();
|
||||
let #len = #name.len();
|
||||
::std::mem::forget(#name);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let abi_ret;
|
||||
@ -417,25 +418,31 @@ fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) {
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: add a test for this
|
||||
Some(ast::Type::String) => {
|
||||
let name = syn::Ident::from("__ret_strlen");
|
||||
let name_ptr = syn::Ident::from("__ret_strlen_ptr");
|
||||
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;
|
||||
});
|
||||
abi_ret = my_quote! { *mut u8 };
|
||||
convert_ret = my_quote! {
|
||||
String::from_utf8_unchecked(
|
||||
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::BorrowedStr) |
|
||||
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! { () };
|
||||
|
Reference in New Issue
Block a user