mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-02 02:11:06 +00:00
Migrate to the failure
crate
Currently errors are reported via Rust panics but there's lots more errors being added over time so this commit starts the movement towards the `failure` crate to more idiomatically report errors as well as provide better error messages over time.
This commit is contained in:
parent
2b9c48d5f9
commit
5f59d95130
@ -19,6 +19,10 @@ matrix:
|
|||||||
rust: nightly
|
rust: nightly
|
||||||
before_script: rustup target add $TARGET
|
before_script: rustup target add $TARGET
|
||||||
script: cargo build --manifest-path crates/cli/Cargo.toml --release --target $TARGET
|
script: cargo build --manifest-path crates/cli/Cargo.toml --release --target $TARGET
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- musl-tools
|
||||||
|
|
||||||
# Dist OSX binary
|
# Dist OSX binary
|
||||||
- os: osx
|
- os: osx
|
||||||
|
@ -12,6 +12,7 @@ Shared support for the wasm-bindgen-cli package, an internal dependency
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = "0.9"
|
base64 = "0.9"
|
||||||
|
failure = "0.1"
|
||||||
parity-wasm = "0.27"
|
parity-wasm = "0.27"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
wasm-bindgen-shared = { path = "../shared", version = '=0.2.5' }
|
wasm-bindgen-shared = { path = "../shared", version = '=0.2.5' }
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use failure::Error;
|
||||||
|
|
||||||
use super::{indent, Context};
|
use super::{indent, Context};
|
||||||
use descriptor::{Descriptor, Function};
|
use descriptor::{Descriptor, Function};
|
||||||
|
|
||||||
@ -59,12 +61,12 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
|
|
||||||
/// Generates all bindings necessary for the signature in `Function`,
|
/// Generates all bindings necessary for the signature in `Function`,
|
||||||
/// creating necessary argument conversions and return value processing.
|
/// creating necessary argument conversions and return value processing.
|
||||||
pub fn process(&mut self, function: &Function) -> &mut Self {
|
pub fn process(&mut self, function: &Function) -> Result<&mut Self, Error> {
|
||||||
for arg in function.arguments.iter() {
|
for arg in function.arguments.iter() {
|
||||||
self.argument(arg);
|
self.argument(arg)?;
|
||||||
}
|
}
|
||||||
self.ret(&function.ret);
|
self.ret(&function.ret)?;
|
||||||
self
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flag this shim as a method call into Rust, so the first Rust argument
|
/// Flag this shim as a method call into Rust, so the first Rust argument
|
||||||
@ -100,7 +102,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn argument(&mut self, arg: &Descriptor) -> &mut Self {
|
pub fn argument(&mut self, arg: &Descriptor) -> Result<&mut Self, Error> {
|
||||||
let i = self.arg_idx;
|
let i = self.arg_idx;
|
||||||
self.arg_idx += 1;
|
self.arg_idx += 1;
|
||||||
let name = format!("arg{}", i);
|
let name = format!("arg{}", i);
|
||||||
@ -108,8 +110,8 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
if let Some(kind) = arg.vector_kind() {
|
if let Some(kind) = arg.vector_kind() {
|
||||||
self.js_arguments.push((name.clone(), kind.js_ty().to_string()));
|
self.js_arguments.push((name.clone(), kind.js_ty().to_string()));
|
||||||
|
|
||||||
let func = self.cx.pass_to_wasm_function(kind);
|
let func = self.cx.pass_to_wasm_function(kind)?;
|
||||||
self.cx.expose_set_global_argument();
|
self.cx.expose_set_global_argument()?;
|
||||||
let global_idx = self.global_idx();
|
let global_idx = self.global_idx();
|
||||||
self.prelude(&format!("\
|
self.prelude(&format!("\
|
||||||
const [ptr{i}, len{i}] = {func}({arg});\n\
|
const [ptr{i}, len{i}] = {func}({arg});\n\
|
||||||
@ -119,10 +121,10 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
self.finally(&format!("\
|
self.finally(&format!("\
|
||||||
wasm.__wbindgen_free(ptr{i}, len{i} * {size});\n\
|
wasm.__wbindgen_free(ptr{i}, len{i} * {size});\n\
|
||||||
", i = i, size = kind.size()));
|
", i = i, size = kind.size()));
|
||||||
self.cx.require_internal_export("__wbindgen_free");
|
self.cx.require_internal_export("__wbindgen_free")?;
|
||||||
}
|
}
|
||||||
self.rust_arguments.push(format!("ptr{}", i));
|
self.rust_arguments.push(format!("ptr{}", i));
|
||||||
return self
|
return Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(s) = arg.rust_struct() {
|
if let Some(s) = arg.rust_struct() {
|
||||||
@ -144,7 +146,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
", i = i, arg = name));
|
", i = i, arg = name));
|
||||||
self.rust_arguments.push(format!("ptr{}", i));
|
self.rust_arguments.push(format!("ptr{}", i));
|
||||||
}
|
}
|
||||||
return self
|
return Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if arg.is_number() {
|
if arg.is_number() {
|
||||||
@ -156,7 +158,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.rust_arguments.push(name);
|
self.rust_arguments.push(name);
|
||||||
return self
|
return Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if arg.is_ref_anyref() {
|
if arg.is_ref_anyref() {
|
||||||
@ -164,7 +166,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
self.cx.expose_borrowed_objects();
|
self.cx.expose_borrowed_objects();
|
||||||
self.finally("stack.pop();");
|
self.finally("stack.pop();");
|
||||||
self.rust_arguments.push(format!("addBorrowedObject({})", name));
|
self.rust_arguments.push(format!("addBorrowedObject({})", name));
|
||||||
return self
|
return Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
match *arg {
|
match *arg {
|
||||||
@ -184,19 +186,19 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
self.rust_arguments.push(format!("addHeapObject({})", name));
|
self.rust_arguments.push(format!("addHeapObject({})", name));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("unsupported argument to rust function {:?}", arg)
|
bail!("unsupported argument to rust function {:?}", arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ret(&mut self, ret: &Option<Descriptor>) -> &mut Self {
|
pub fn ret(&mut self, ret: &Option<Descriptor>) -> Result<&mut Self, Error> {
|
||||||
let ty = match *ret {
|
let ty = match *ret {
|
||||||
Some(ref t) => t,
|
Some(ref t) => t,
|
||||||
None => {
|
None => {
|
||||||
self.ret_ty = "void".to_string();
|
self.ret_ty = "void".to_string();
|
||||||
self.ret_expr = format!("return RET;");
|
self.ret_expr = format!("return RET;");
|
||||||
return self
|
return Ok(self)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -204,18 +206,18 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
self.ret_ty = "any".to_string();
|
self.ret_ty = "any".to_string();
|
||||||
self.cx.expose_get_object();
|
self.cx.expose_get_object();
|
||||||
self.ret_expr = format!("return getObject(RET);");
|
self.ret_expr = format!("return getObject(RET);");
|
||||||
return self
|
return Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ty.is_by_ref() {
|
if ty.is_by_ref() {
|
||||||
panic!("cannot return references from Rust to JS yet")
|
bail!("cannot return references from Rust to JS yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ty) = ty.vector_kind() {
|
if let Some(ty) = ty.vector_kind() {
|
||||||
self.ret_ty = ty.js_ty().to_string();
|
self.ret_ty = ty.js_ty().to_string();
|
||||||
let f = self.cx.expose_get_vector_from_wasm(ty);
|
let f = self.cx.expose_get_vector_from_wasm(ty);
|
||||||
self.cx.expose_get_global_argument();
|
self.cx.expose_get_global_argument()?;
|
||||||
self.cx.require_internal_export("__wbindgen_free");
|
self.cx.require_internal_export("__wbindgen_free")?;
|
||||||
self.ret_expr = format!("\
|
self.ret_expr = format!("\
|
||||||
const ret = RET;\n\
|
const ret = RET;\n\
|
||||||
const len = getGlobalArgument(0);\n\
|
const len = getGlobalArgument(0);\n\
|
||||||
@ -223,19 +225,19 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
wasm.__wbindgen_free(ret, len * {});\n\
|
wasm.__wbindgen_free(ret, len * {});\n\
|
||||||
return realRet;\n\
|
return realRet;\n\
|
||||||
", f, ty.size());
|
", f, ty.size());
|
||||||
return self
|
return Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(name) = ty.rust_struct() {
|
if let Some(name) = ty.rust_struct() {
|
||||||
self.ret_ty = name.to_string();
|
self.ret_ty = name.to_string();
|
||||||
self.ret_expr = format!("return {name}.__construct(RET);", name = name);
|
self.ret_expr = format!("return {name}.__construct(RET);", name = name);
|
||||||
return self
|
return Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ty.is_number() {
|
if ty.is_number() {
|
||||||
self.ret_ty = "number".to_string();
|
self.ret_ty = "number".to_string();
|
||||||
self.ret_expr = format!("return RET;");
|
self.ret_expr = format!("return RET;");
|
||||||
return self
|
return Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
match *ty {
|
match *ty {
|
||||||
@ -248,9 +250,9 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
self.cx.expose_take_object();
|
self.cx.expose_take_object();
|
||||||
self.ret_expr = format!("return takeObject(RET);");
|
self.ret_expr = format!("return takeObject(RET);");
|
||||||
}
|
}
|
||||||
_ => panic!("unsupported return from Rust to JS {:?}", ty),
|
_ => bail!("unsupported return from Rust to JS {:?}", ty),
|
||||||
}
|
}
|
||||||
self
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate the actual function.
|
/// Generate the actual function.
|
||||||
|
@ -2,6 +2,7 @@ use std::collections::{HashSet, HashMap};
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
use failure::{Error, ResultExt};
|
||||||
use parity_wasm::elements::*;
|
use parity_wasm::elements::*;
|
||||||
use parity_wasm;
|
use parity_wasm;
|
||||||
use shared;
|
use shared;
|
||||||
@ -68,33 +69,38 @@ impl<'a> Context<'a> {
|
|||||||
self.global(&global);
|
self.global(&global);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_internal_export(&mut self, name: &'static str) {
|
fn require_internal_export(&mut self, name: &'static str)
|
||||||
|
-> Result<(), Error>
|
||||||
|
{
|
||||||
if !self.required_internal_exports.insert(name) {
|
if !self.required_internal_exports.insert(name) {
|
||||||
return
|
return Ok(())
|
||||||
}
|
}
|
||||||
if let Some(s) = self.module.export_section() {
|
if let Some(s) = self.module.export_section() {
|
||||||
if s.entries().iter().any(|e| e.field() == name) {
|
if s.entries().iter().any(|e| e.field() == name) {
|
||||||
return
|
return Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic!("\n\nthe exported function `{}` is required to generate bindings \
|
bail!("\n\nthe exported function `{}` is required to generate bindings \
|
||||||
but it was not found in the wasm file, perhaps the `std` feature \
|
but it was not found in the wasm file, perhaps the `std` feature \
|
||||||
of the `wasm-bindgen` crate needs to be enabled?\n\n",
|
of the `wasm-bindgen` crate needs to be enabled?\n\n",
|
||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finalize(&mut self, module_name: &str) -> (String, String) {
|
pub fn finalize(&mut self, module_name: &str) -> Result<(String, String), Error> {
|
||||||
self.unexport_unused_internal_exports();
|
self.unexport_unused_internal_exports();
|
||||||
self.gc();
|
self.gc()?;
|
||||||
self.write_classes();
|
self.write_classes()?;
|
||||||
{
|
{
|
||||||
let mut bind = |name: &str, f: &Fn(&mut Self) -> String| {
|
let mut bind = |name: &str, f: &Fn(&mut Self) -> Result<String, Error>|
|
||||||
|
-> Result<(), Error>
|
||||||
|
{
|
||||||
if !self.wasm_import_needed(name) {
|
if !self.wasm_import_needed(name) {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
let contents = f(self);
|
let contents = f(self)?;
|
||||||
self.export(name, &contents);
|
self.export(name, &contents);
|
||||||
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
bind("__wbindgen_object_clone_ref", &|me| {
|
bind("__wbindgen_object_clone_ref", &|me| {
|
||||||
@ -109,7 +115,7 @@ impl<'a> Context<'a> {
|
|||||||
} else {
|
} else {
|
||||||
String::from("val.cnt += 1;")
|
String::from("val.cnt += 1;")
|
||||||
};
|
};
|
||||||
format!("
|
Ok(format!("
|
||||||
function(idx) {{
|
function(idx) {{
|
||||||
// If this object is on the stack promote it to the heap.
|
// If this object is on the stack promote it to the heap.
|
||||||
if ((idx & 1) === 1)
|
if ((idx & 1) === 1)
|
||||||
@ -121,33 +127,33 @@ impl<'a> Context<'a> {
|
|||||||
{}
|
{}
|
||||||
return idx;
|
return idx;
|
||||||
}}
|
}}
|
||||||
", bump_cnt)
|
", bump_cnt))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_object_drop_ref", &|me| {
|
bind("__wbindgen_object_drop_ref", &|me| {
|
||||||
me.expose_drop_ref();
|
me.expose_drop_ref();
|
||||||
"function(i) { dropRef(i); }".to_string()
|
Ok("function(i) { dropRef(i); }".to_string())
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_string_new", &|me| {
|
bind("__wbindgen_string_new", &|me| {
|
||||||
me.expose_add_heap_object();
|
me.expose_add_heap_object();
|
||||||
me.expose_get_string_from_wasm();
|
me.expose_get_string_from_wasm();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function(p, l) {
|
function(p, l) {
|
||||||
return addHeapObject(getStringFromWasm(p, l));
|
return addHeapObject(getStringFromWasm(p, l));
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_number_new", &|me| {
|
bind("__wbindgen_number_new", &|me| {
|
||||||
me.expose_add_heap_object();
|
me.expose_add_heap_object();
|
||||||
String::from("function(i) { return addHeapObject(i); }")
|
Ok(String::from("function(i) { return addHeapObject(i); }"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_number_get", &|me| {
|
bind("__wbindgen_number_get", &|me| {
|
||||||
me.expose_get_object();
|
me.expose_get_object();
|
||||||
me.expose_uint8_memory();
|
me.expose_uint8_memory();
|
||||||
format!("
|
Ok(format!("
|
||||||
function(n, invalid) {{
|
function(n, invalid) {{
|
||||||
let obj = getObject(n);
|
let obj = getObject(n);
|
||||||
if (typeof(obj) === 'number')
|
if (typeof(obj) === 'number')
|
||||||
@ -155,53 +161,53 @@ impl<'a> Context<'a> {
|
|||||||
getUint8Memory()[invalid] = 1;
|
getUint8Memory()[invalid] = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}}
|
}}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_undefined_new", &|me| {
|
bind("__wbindgen_undefined_new", &|me| {
|
||||||
me.expose_add_heap_object();
|
me.expose_add_heap_object();
|
||||||
String::from("function() { return addHeapObject(undefined); }")
|
Ok(String::from("function() { return addHeapObject(undefined); }"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_null_new", &|me| {
|
bind("__wbindgen_null_new", &|me| {
|
||||||
me.expose_add_heap_object();
|
me.expose_add_heap_object();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function() {
|
function() {
|
||||||
return addHeapObject(null);
|
return addHeapObject(null);
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_is_null", &|me| {
|
bind("__wbindgen_is_null", &|me| {
|
||||||
me.expose_get_object();
|
me.expose_get_object();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function(idx) {
|
function(idx) {
|
||||||
return getObject(idx) === null ? 1 : 0;
|
return getObject(idx) === null ? 1 : 0;
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_is_undefined", &|me| {
|
bind("__wbindgen_is_undefined", &|me| {
|
||||||
me.expose_get_object();
|
me.expose_get_object();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function(idx) {
|
function(idx) {
|
||||||
return getObject(idx) === undefined ? 1 : 0;
|
return getObject(idx) === undefined ? 1 : 0;
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_boolean_new", &|me| {
|
bind("__wbindgen_boolean_new", &|me| {
|
||||||
me.expose_add_heap_object();
|
me.expose_add_heap_object();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function(v) {
|
function(v) {
|
||||||
return addHeapObject(v === 1);
|
return addHeapObject(v === 1);
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_boolean_get", &|me| {
|
bind("__wbindgen_boolean_get", &|me| {
|
||||||
me.expose_get_object();
|
me.expose_get_object();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function(i) {
|
function(i) {
|
||||||
let v = getObject(i);
|
let v = getObject(i);
|
||||||
if (typeof(v) === 'boolean') {
|
if (typeof(v) === 'boolean') {
|
||||||
@ -210,13 +216,13 @@ impl<'a> Context<'a> {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_symbol_new", &|me| {
|
bind("__wbindgen_symbol_new", &|me| {
|
||||||
me.expose_get_string_from_wasm();
|
me.expose_get_string_from_wasm();
|
||||||
me.expose_add_heap_object();
|
me.expose_add_heap_object();
|
||||||
format!("
|
Ok(format!("
|
||||||
function(ptr, len) {{
|
function(ptr, len) {{
|
||||||
let a;
|
let a;
|
||||||
console.log(ptr, len);
|
console.log(ptr, len);
|
||||||
@ -227,32 +233,32 @@ impl<'a> Context<'a> {
|
|||||||
}}
|
}}
|
||||||
return addHeapObject(a);
|
return addHeapObject(a);
|
||||||
}}
|
}}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_is_symbol", &|me| {
|
bind("__wbindgen_is_symbol", &|me| {
|
||||||
me.expose_get_object();
|
me.expose_get_object();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function(i) {
|
function(i) {
|
||||||
return typeof(getObject(i)) === 'symbol' ? 1 : 0;
|
return typeof(getObject(i)) === 'symbol' ? 1 : 0;
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_throw", &|me| {
|
bind("__wbindgen_throw", &|me| {
|
||||||
me.expose_get_string_from_wasm();
|
me.expose_get_string_from_wasm();
|
||||||
format!("
|
Ok(format!("
|
||||||
function(ptr, len) {{
|
function(ptr, len) {{
|
||||||
throw new Error(getStringFromWasm(ptr, len));
|
throw new Error(getStringFromWasm(ptr, len));
|
||||||
}}
|
}}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_string_get", &|me| {
|
bind("__wbindgen_string_get", &|me| {
|
||||||
me.expose_pass_string_to_wasm();
|
me.expose_pass_string_to_wasm()?;
|
||||||
me.expose_get_object();
|
me.expose_get_object();
|
||||||
me.expose_uint32_memory();
|
me.expose_uint32_memory();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function(i, len_ptr) {
|
function(i, len_ptr) {
|
||||||
let obj = getObject(i);
|
let obj = getObject(i);
|
||||||
if (typeof(obj) !== 'string')
|
if (typeof(obj) !== 'string')
|
||||||
@ -261,27 +267,27 @@ impl<'a> Context<'a> {
|
|||||||
getUint32Memory()[len_ptr / 4] = len;
|
getUint32Memory()[len_ptr / 4] = len;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
|
|
||||||
bind("__wbindgen_cb_drop", &|me| {
|
bind("__wbindgen_cb_drop", &|me| {
|
||||||
me.expose_drop_ref();
|
me.expose_drop_ref();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function(i) {
|
function(i) {
|
||||||
let obj = getObject(i).original;
|
let obj = getObject(i).original;
|
||||||
obj.a = obj.b = 0;
|
obj.a = obj.b = 0;
|
||||||
dropRef(i);
|
dropRef(i);
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
bind("__wbindgen_cb_forget", &|me| {
|
bind("__wbindgen_cb_forget", &|me| {
|
||||||
me.expose_drop_ref();
|
me.expose_drop_ref();
|
||||||
String::from("
|
Ok(String::from("
|
||||||
function(i) {
|
function(i) {
|
||||||
dropRef(i);
|
dropRef(i);
|
||||||
}
|
}
|
||||||
")
|
"))
|
||||||
});
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.rewrite_imports(module_name);
|
self.rewrite_imports(module_name);
|
||||||
@ -335,23 +341,24 @@ impl<'a> Context<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.export_table();
|
self.export_table();
|
||||||
self.gc();
|
self.gc()?;
|
||||||
|
|
||||||
while js.contains("\n\n\n") {
|
while js.contains("\n\n\n") {
|
||||||
js = js.replace("\n\n\n", "\n\n");
|
js = js.replace("\n\n\n", "\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
(js, self.typescript.clone())
|
Ok((js, self.typescript.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_classes(&mut self) {
|
fn write_classes(&mut self) -> Result<(), Error> {
|
||||||
let classes = mem::replace(&mut self.exported_classes, Default::default());
|
let classes = mem::replace(&mut self.exported_classes, Default::default());
|
||||||
for (class, exports) in classes {
|
for (class, exports) in classes {
|
||||||
self.write_class(&class, &exports);
|
self.write_class(&class, &exports)?;
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_class(&mut self, name: &str, class: &ExportedClass) {
|
fn write_class(&mut self, name: &str, class: &ExportedClass) -> Result<(), Error> {
|
||||||
let mut dst = format!("class {} {{\n", name);
|
let mut dst = format!("class {} {{\n", name);
|
||||||
let mut ts_dst = format!("export {}", dst);
|
let mut ts_dst = format!("export {}", dst);
|
||||||
|
|
||||||
@ -415,8 +422,8 @@ impl<'a> Context<'a> {
|
|||||||
let set = {
|
let set = {
|
||||||
let mut cx = Js2Rust::new(&field.name, self);
|
let mut cx = Js2Rust::new(&field.name, self);
|
||||||
cx.method(true)
|
cx.method(true)
|
||||||
.argument(&descriptor)
|
.argument(&descriptor)?
|
||||||
.ret(&None);
|
.ret(&None)?;
|
||||||
ts_dst.push_str(&format!("{}{}: {}\n",
|
ts_dst.push_str(&format!("{}{}: {}\n",
|
||||||
if field.readonly { "readonly " } else { "" },
|
if field.readonly { "readonly " } else { "" },
|
||||||
field.name,
|
field.name,
|
||||||
@ -425,7 +432,7 @@ impl<'a> Context<'a> {
|
|||||||
};
|
};
|
||||||
let (get, _ts) = Js2Rust::new(&field.name, self)
|
let (get, _ts) = Js2Rust::new(&field.name, self)
|
||||||
.method(true)
|
.method(true)
|
||||||
.ret(&Some(descriptor))
|
.ret(&Some(descriptor))?
|
||||||
.finish("", &format!("wasm.{}", wasm_getter));
|
.finish("", &format!("wasm.{}", wasm_getter));
|
||||||
|
|
||||||
dst.push_str("get ");
|
dst.push_str("get ");
|
||||||
@ -455,6 +462,8 @@ impl<'a> Context<'a> {
|
|||||||
|
|
||||||
self.export(&name, &dst);
|
self.export(&name, &dst);
|
||||||
self.typescript.push_str(&ts_dst);
|
self.typescript.push_str(&ts_dst);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_table(&mut self) {
|
fn export_table(&mut self) {
|
||||||
@ -697,11 +706,11 @@ impl<'a> Context<'a> {
|
|||||||
"));
|
"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_pass_string_to_wasm(&mut self) {
|
fn expose_pass_string_to_wasm(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("pass_string_to_wasm") {
|
if !self.exposed_globals.insert("pass_string_to_wasm") {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.require_internal_export("__wbindgen_malloc");
|
self.require_internal_export("__wbindgen_malloc")?;
|
||||||
self.expose_text_encoder();
|
self.expose_text_encoder();
|
||||||
self.expose_uint8_memory();
|
self.expose_uint8_memory();
|
||||||
let debug = if self.config.debug {
|
let debug = if self.config.debug {
|
||||||
@ -721,13 +730,14 @@ impl<'a> Context<'a> {
|
|||||||
return [ptr, buf.length];
|
return [ptr, buf.length];
|
||||||
}}
|
}}
|
||||||
", debug));
|
", debug));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_pass_array8_to_wasm(&mut self) {
|
fn expose_pass_array8_to_wasm(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("pass_array8_to_wasm") {
|
if !self.exposed_globals.insert("pass_array8_to_wasm") {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.require_internal_export("__wbindgen_malloc");
|
self.require_internal_export("__wbindgen_malloc")?;
|
||||||
self.expose_uint8_memory();
|
self.expose_uint8_memory();
|
||||||
self.global(&format!("
|
self.global(&format!("
|
||||||
function passArray8ToWasm(arg) {{
|
function passArray8ToWasm(arg) {{
|
||||||
@ -736,13 +746,14 @@ impl<'a> Context<'a> {
|
|||||||
return [ptr, arg.length];
|
return [ptr, arg.length];
|
||||||
}}
|
}}
|
||||||
"));
|
"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_pass_array16_to_wasm(&mut self) {
|
fn expose_pass_array16_to_wasm(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("pass_array16_to_wasm") {
|
if !self.exposed_globals.insert("pass_array16_to_wasm") {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.require_internal_export("__wbindgen_malloc");
|
self.require_internal_export("__wbindgen_malloc")?;
|
||||||
self.expose_uint16_memory();
|
self.expose_uint16_memory();
|
||||||
self.global(&format!("
|
self.global(&format!("
|
||||||
function passArray16ToWasm(arg) {{
|
function passArray16ToWasm(arg) {{
|
||||||
@ -751,13 +762,14 @@ impl<'a> Context<'a> {
|
|||||||
return [ptr, arg.length];
|
return [ptr, arg.length];
|
||||||
}}
|
}}
|
||||||
"));
|
"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_pass_array32_to_wasm(&mut self) {
|
fn expose_pass_array32_to_wasm(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("pass_array32_to_wasm") {
|
if !self.exposed_globals.insert("pass_array32_to_wasm") {
|
||||||
return;
|
return Ok(())
|
||||||
}
|
}
|
||||||
self.require_internal_export("__wbindgen_malloc");
|
self.require_internal_export("__wbindgen_malloc")?;
|
||||||
self.expose_uint32_memory();
|
self.expose_uint32_memory();
|
||||||
self.global(&format!("
|
self.global(&format!("
|
||||||
function passArray32ToWasm(arg) {{
|
function passArray32ToWasm(arg) {{
|
||||||
@ -766,13 +778,14 @@ impl<'a> Context<'a> {
|
|||||||
return [ptr, arg.length];
|
return [ptr, arg.length];
|
||||||
}}
|
}}
|
||||||
"));
|
"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_pass_array_f32_to_wasm(&mut self) {
|
fn expose_pass_array_f32_to_wasm(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("pass_array_f32_to_wasm") {
|
if !self.exposed_globals.insert("pass_array_f32_to_wasm") {
|
||||||
return;
|
return Ok(())
|
||||||
}
|
}
|
||||||
self.require_internal_export("__wbindgen_malloc");
|
self.require_internal_export("__wbindgen_malloc")?;
|
||||||
self.global(&format!("
|
self.global(&format!("
|
||||||
function passArrayF32ToWasm(arg) {{
|
function passArrayF32ToWasm(arg) {{
|
||||||
const ptr = wasm.__wbindgen_malloc(arg.length * 4);
|
const ptr = wasm.__wbindgen_malloc(arg.length * 4);
|
||||||
@ -780,13 +793,14 @@ impl<'a> Context<'a> {
|
|||||||
return [ptr, arg.length];
|
return [ptr, arg.length];
|
||||||
}}
|
}}
|
||||||
"));
|
"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_pass_array_f64_to_wasm(&mut self) {
|
fn expose_pass_array_f64_to_wasm(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("pass_array_f64_to_wasm") {
|
if !self.exposed_globals.insert("pass_array_f64_to_wasm") {
|
||||||
return;
|
return Ok(())
|
||||||
}
|
}
|
||||||
self.require_internal_export("__wbindgen_malloc");
|
self.require_internal_export("__wbindgen_malloc")?;
|
||||||
self.global(&format!("
|
self.global(&format!("
|
||||||
function passArrayF64ToWasm(arg) {{
|
function passArrayF64ToWasm(arg) {{
|
||||||
const ptr = wasm.__wbindgen_malloc(arg.length * 8);
|
const ptr = wasm.__wbindgen_malloc(arg.length * 8);
|
||||||
@ -794,6 +808,7 @@ impl<'a> Context<'a> {
|
|||||||
return [ptr, arg.length];
|
return [ptr, arg.length];
|
||||||
}}
|
}}
|
||||||
"));
|
"));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_text_encoder(&mut self) {
|
fn expose_text_encoder(&mut self) {
|
||||||
@ -1119,39 +1134,40 @@ impl<'a> Context<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pass_to_wasm_function(&mut self, t: VectorKind) -> &'static str {
|
fn pass_to_wasm_function(&mut self, t: VectorKind) -> Result<&'static str, Error> {
|
||||||
match t {
|
let s = match t {
|
||||||
VectorKind::String => {
|
VectorKind::String => {
|
||||||
self.expose_pass_string_to_wasm();
|
self.expose_pass_string_to_wasm()?;
|
||||||
"passStringToWasm"
|
"passStringToWasm"
|
||||||
}
|
}
|
||||||
VectorKind::I8 |
|
VectorKind::I8 |
|
||||||
VectorKind::U8 => {
|
VectorKind::U8 => {
|
||||||
self.expose_pass_array8_to_wasm();
|
self.expose_pass_array8_to_wasm()?;
|
||||||
"passArray8ToWasm"
|
"passArray8ToWasm"
|
||||||
}
|
}
|
||||||
VectorKind::U16 |
|
VectorKind::U16 |
|
||||||
VectorKind::I16 => {
|
VectorKind::I16 => {
|
||||||
self.expose_pass_array16_to_wasm();
|
self.expose_pass_array16_to_wasm()?;
|
||||||
"passArray16ToWasm"
|
"passArray16ToWasm"
|
||||||
}
|
}
|
||||||
VectorKind::I32 |
|
VectorKind::I32 |
|
||||||
VectorKind::U32 => {
|
VectorKind::U32 => {
|
||||||
self.expose_pass_array32_to_wasm();
|
self.expose_pass_array32_to_wasm()?;
|
||||||
"passArray32ToWasm"
|
"passArray32ToWasm"
|
||||||
}
|
}
|
||||||
VectorKind::F32 => {
|
VectorKind::F32 => {
|
||||||
self.expose_pass_array_f32_to_wasm();
|
self.expose_pass_array_f32_to_wasm()?;
|
||||||
"passArrayF32ToWasm"
|
"passArrayF32ToWasm"
|
||||||
}
|
}
|
||||||
VectorKind::F64 => {
|
VectorKind::F64 => {
|
||||||
self.expose_pass_array_f64_to_wasm();
|
self.expose_pass_array_f64_to_wasm()?;
|
||||||
"passArrayF64ToWasm"
|
"passArrayF64ToWasm"
|
||||||
}
|
}
|
||||||
VectorKind::Anyref => {
|
VectorKind::Anyref => {
|
||||||
panic!("cannot pass list of JsValue to wasm yet")
|
bail!("cannot pass list of JsValue to wasm yet")
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_get_vector_from_wasm(&mut self, ty: VectorKind) -> &'static str {
|
fn expose_get_vector_from_wasm(&mut self, ty: VectorKind) -> &'static str {
|
||||||
@ -1199,39 +1215,41 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_set_global_argument(&mut self) {
|
fn expose_set_global_argument(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("set_global_argument") {
|
if !self.exposed_globals.insert("set_global_argument") {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.expose_uint32_memory();
|
self.expose_uint32_memory();
|
||||||
self.expose_global_argument_ptr();
|
self.expose_global_argument_ptr()?;
|
||||||
self.global("
|
self.global("
|
||||||
function setGlobalArgument(arg, i) {
|
function setGlobalArgument(arg, i) {
|
||||||
const idx = globalArgumentPtr() / 4 + i;
|
const idx = globalArgumentPtr() / 4 + i;
|
||||||
getUint32Memory()[idx] = arg;
|
getUint32Memory()[idx] = arg;
|
||||||
}
|
}
|
||||||
");
|
");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_get_global_argument(&mut self) {
|
fn expose_get_global_argument(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("get_global_argument") {
|
if !self.exposed_globals.insert("get_global_argument") {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.expose_uint32_memory();
|
self.expose_uint32_memory();
|
||||||
self.expose_global_argument_ptr();
|
self.expose_global_argument_ptr()?;
|
||||||
self.global("
|
self.global("
|
||||||
function getGlobalArgument(arg) {
|
function getGlobalArgument(arg) {
|
||||||
const idx = globalArgumentPtr() / 4 + arg;
|
const idx = globalArgumentPtr() / 4 + arg;
|
||||||
return getUint32Memory()[idx];
|
return getUint32Memory()[idx];
|
||||||
}
|
}
|
||||||
");
|
");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_global_argument_ptr(&mut self) {
|
fn expose_global_argument_ptr(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("global_argument_ptr") {
|
if !self.exposed_globals.insert("global_argument_ptr") {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.require_internal_export("__wbindgen_global_argument_ptr");
|
self.require_internal_export("__wbindgen_global_argument_ptr")?;
|
||||||
self.global("
|
self.global("
|
||||||
let cachedGlobalArgumentPtr = null;
|
let cachedGlobalArgumentPtr = null;
|
||||||
function globalArgumentPtr() {
|
function globalArgumentPtr() {
|
||||||
@ -1240,6 +1258,7 @@ impl<'a> Context<'a> {
|
|||||||
return cachedGlobalArgumentPtr;
|
return cachedGlobalArgumentPtr;
|
||||||
}
|
}
|
||||||
");
|
");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_get_inherited_descriptor(&mut self) {
|
fn expose_get_inherited_descriptor(&mut self) {
|
||||||
@ -1267,14 +1286,14 @@ impl<'a> Context<'a> {
|
|||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gc(&mut self) {
|
fn gc(&mut self) -> Result<(), Error> {
|
||||||
let module = mem::replace(self.module, Module::default());
|
let module = mem::replace(self.module, Module::default());
|
||||||
let wasm_bytes = parity_wasm::serialize(module).unwrap();
|
let wasm_bytes = parity_wasm::serialize(module)?;
|
||||||
let bytes = wasm_gc::Config::new()
|
let bytes = wasm_gc::Config::new()
|
||||||
.demangle(self.config.demangle)
|
.demangle(self.config.demangle)
|
||||||
.gc(&wasm_bytes)
|
.gc(&wasm_bytes)?;
|
||||||
.unwrap();
|
*self.module = deserialize_buffer(&bytes)?;
|
||||||
*self.module = deserialize_buffer(&bytes).unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn describe(&self, name: &str) -> Descriptor {
|
fn describe(&self, name: &str) -> Descriptor {
|
||||||
@ -1298,12 +1317,16 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> SubContext<'a, 'b> {
|
impl<'a, 'b> SubContext<'a, 'b> {
|
||||||
pub fn generate(&mut self) {
|
pub fn generate(&mut self) -> Result<(), Error> {
|
||||||
for f in self.program.exports.iter() {
|
for f in self.program.exports.iter() {
|
||||||
self.generate_export(f);
|
self.generate_export(f)
|
||||||
|
.with_context(|_| {
|
||||||
|
format!("failed to generate bindings for Rust export `{}`",
|
||||||
|
f.function.name)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
for f in self.program.imports.iter() {
|
for f in self.program.imports.iter() {
|
||||||
self.generate_import(f);
|
self.generate_import(f)?;
|
||||||
}
|
}
|
||||||
for e in self.program.enums.iter() {
|
for e in self.program.enums.iter() {
|
||||||
self.generate_enum(e);
|
self.generate_enum(e);
|
||||||
@ -1320,29 +1343,38 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_export(&mut self, export: &shared::Export) {
|
fn generate_export(&mut self, export: &shared::Export)
|
||||||
|
-> Result<(), Error>
|
||||||
|
{
|
||||||
if let Some(ref class) = export.class {
|
if let Some(ref class) = export.class {
|
||||||
return self.generate_export_for_class(class, export);
|
return self.generate_export_for_class(class, export);
|
||||||
}
|
}
|
||||||
let descriptor = self.cx.describe(&export.function.name);
|
let descriptor = self.cx.describe(&export.function.name);
|
||||||
let (js, ts) = Js2Rust::new(&export.function.name, self.cx)
|
let (js, ts) = Js2Rust::new(&export.function.name, self.cx)
|
||||||
.process(descriptor.unwrap_function())
|
.process(descriptor.unwrap_function())?
|
||||||
.finish("function", &format!("wasm.{}", export.function.name));
|
.finish("function", &format!("wasm.{}", export.function.name));
|
||||||
self.cx.export(&export.function.name, &js);
|
self.cx.export(&export.function.name, &js);
|
||||||
self.cx.globals.push_str("\n");
|
self.cx.globals.push_str("\n");
|
||||||
self.cx.typescript.push_str("export ");
|
self.cx.typescript.push_str("export ");
|
||||||
self.cx.typescript.push_str(&ts);
|
self.cx.typescript.push_str(&ts);
|
||||||
self.cx.typescript.push_str("\n");
|
self.cx.typescript.push_str("\n");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_export_for_class(&mut self, class_name: &str, export: &shared::Export) {
|
fn generate_export_for_class(
|
||||||
|
&mut self,
|
||||||
|
class_name: &str,
|
||||||
|
export: &shared::Export,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let wasm_name = shared::struct_function_export_name(class_name, &export.function.name);
|
let wasm_name = shared::struct_function_export_name(class_name, &export.function.name);
|
||||||
let descriptor = self.cx.describe(&wasm_name);
|
let descriptor = self.cx.describe(&wasm_name);
|
||||||
let (js, ts) = Js2Rust::new(&export.function.name, self.cx)
|
let (js, ts) = Js2Rust::new(&export.function.name, self.cx)
|
||||||
.method(export.method)
|
.method(export.method)
|
||||||
.process(descriptor.unwrap_function())
|
.process(descriptor.unwrap_function())?
|
||||||
.finish("", &format!("wasm.{}", wasm_name));
|
.finish("", &format!("wasm.{}", wasm_name));
|
||||||
let class = self.cx.exported_classes.entry(class_name.to_string())
|
let class = self.cx.exported_classes.entry(class_name.to_string())
|
||||||
.or_insert(ExportedClass::default());
|
.or_insert(ExportedClass::default());
|
||||||
@ -1360,7 +1392,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
class.constructor = match constructors.len() {
|
class.constructor = match constructors.len() {
|
||||||
0 => None,
|
0 => None,
|
||||||
1 => Some(constructors[0].clone()),
|
1 => Some(constructors[0].clone()),
|
||||||
x @ _ => panic!("There must be only one constructor, not {}", x),
|
x @ _ => bail!("there must be only one constructor, not {}", x),
|
||||||
};
|
};
|
||||||
|
|
||||||
class.contents.push_str(&export.function.name);
|
class.contents.push_str(&export.function.name);
|
||||||
@ -1368,44 +1400,61 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
class.contents.push_str("\n");
|
class.contents.push_str("\n");
|
||||||
class.typescript.push_str(&ts);
|
class.typescript.push_str(&ts);
|
||||||
class.typescript.push_str("\n");
|
class.typescript.push_str("\n");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_import(&mut self, import: &shared::Import) {
|
fn generate_import(&mut self, import: &shared::Import) -> Result<(), Error> {
|
||||||
match import.kind {
|
match import.kind {
|
||||||
shared::ImportKind::Function(ref f) => {
|
shared::ImportKind::Function(ref f) => {
|
||||||
self.generate_import_function(import, f)
|
self.generate_import_function(import, f)
|
||||||
|
.with_context(|_| {
|
||||||
|
format!("failed to generate bindings for JS import `{}`",
|
||||||
|
f.function.name)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
shared::ImportKind::Static(ref s) => {
|
shared::ImportKind::Static(ref s) => {
|
||||||
self.generate_import_static(import, s)
|
self.generate_import_static(import, s)
|
||||||
|
.with_context(|_| {
|
||||||
|
format!("failed to generate bindings for JS import `{}`",
|
||||||
|
s.name)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
shared::ImportKind::Type(_) => {}
|
shared::ImportKind::Type(_) => {}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_import_static(&mut self,
|
fn generate_import_static(
|
||||||
info: &shared::Import,
|
&mut self,
|
||||||
import: &shared::ImportStatic) {
|
info: &shared::Import,
|
||||||
|
import: &shared::ImportStatic,
|
||||||
|
)
|
||||||
|
-> Result<(), Error>
|
||||||
|
{
|
||||||
// TODO: should support more types to import here
|
// TODO: should support more types to import here
|
||||||
let obj = self.import_name(info, &import.name);
|
let obj = self.import_name(info, &import.name)?;
|
||||||
self.cx.expose_add_heap_object();
|
self.cx.expose_add_heap_object();
|
||||||
self.cx.export(&import.shim, &format!("
|
self.cx.export(&import.shim, &format!("
|
||||||
function() {{
|
function() {{
|
||||||
return addHeapObject({});
|
return addHeapObject({});
|
||||||
}}
|
}}
|
||||||
", obj));
|
", obj));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_import_function(&mut self,
|
fn generate_import_function(&mut self,
|
||||||
info: &shared::Import,
|
info: &shared::Import,
|
||||||
import: &shared::ImportFunction) {
|
import: &shared::ImportFunction)
|
||||||
|
-> Result<(), Error>
|
||||||
|
{
|
||||||
let descriptor = self.cx.describe(&import.shim);
|
let descriptor = self.cx.describe(&import.shim);
|
||||||
|
|
||||||
let target = match import.class {
|
let target = match import.class {
|
||||||
Some(ref class) if import.js_new => {
|
Some(ref class) if import.js_new => {
|
||||||
format!("new {}", self.import_name(info, class))
|
format!("new {}", self.import_name(info, class)?)
|
||||||
}
|
}
|
||||||
Some(ref class) if import.method => {
|
Some(ref class) if import.method => {
|
||||||
let class = self.import_name(info, class);
|
let class = self.import_name(info, class)?;
|
||||||
let target = if let Some(ref g) = import.getter {
|
let target = if let Some(ref g) = import.getter {
|
||||||
if import.structural {
|
if import.structural {
|
||||||
format!("function() {{ return this.{}; }}", g)
|
format!("function() {{ return this.{}; }}", g)
|
||||||
@ -1461,14 +1510,14 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
format!("{}_target.call", import.shim)
|
format!("{}_target.call", import.shim)
|
||||||
}
|
}
|
||||||
Some(ref class) => {
|
Some(ref class) => {
|
||||||
let class = self.import_name(info, class);
|
let class = self.import_name(info, class)?;
|
||||||
self.cx.global(&format!("
|
self.cx.global(&format!("
|
||||||
const {}_target = {}.{};
|
const {}_target = {}.{};
|
||||||
", import.shim, class, import.function.name));
|
", import.shim, class, import.function.name));
|
||||||
format!("{}_target", import.shim)
|
format!("{}_target", import.shim)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let name = self.import_name(info, &import.function.name);
|
let name = self.import_name(info, &import.function.name)?;
|
||||||
if name.contains(".") {
|
if name.contains(".") {
|
||||||
self.cx.global(&format!("
|
self.cx.global(&format!("
|
||||||
const {}_target = {};
|
const {}_target = {};
|
||||||
@ -1482,12 +1531,13 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
|
|
||||||
let js = Rust2Js::new(self.cx)
|
let js = Rust2Js::new(self.cx)
|
||||||
.catch(import.catch)
|
.catch(import.catch)
|
||||||
.process(descriptor.unwrap_function())
|
.process(descriptor.unwrap_function())?
|
||||||
.finish(&target);
|
.finish(&target);
|
||||||
self.cx.export(&import.shim, &js);
|
self.cx.export(&import.shim, &js);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_enum(&mut self, enum_: &shared::Enum) {
|
fn generate_enum(&mut self, enum_: &shared::Enum) {
|
||||||
let mut variants = String::new();
|
let mut variants = String::new();
|
||||||
|
|
||||||
for variant in enum_.variants.iter() {
|
for variant in enum_.variants.iter() {
|
||||||
@ -1504,10 +1554,13 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
self.cx.typescript.push_str("}\n");
|
self.cx.typescript.push_str("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_name(&mut self, import: &shared::Import, item: &str) -> String {
|
fn import_name(&mut self, import: &shared::Import, item: &str)
|
||||||
|
-> Result<String, Error>
|
||||||
|
{
|
||||||
if let Some(ref module) = import.module {
|
if let Some(ref module) = import.module {
|
||||||
if self.cx.config.no_modules {
|
if self.cx.config.no_modules {
|
||||||
panic!("import from `{}` module not allowed in `--no-modules`. use `--nodejs` or `--browser` instead", module);
|
bail!("import from `{}` module not allowed with `--no-modules`; \
|
||||||
|
use `--nodejs` or `--browser` instead", module);
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = import.js_namespace.as_ref().map(|s| &**s).unwrap_or(item);
|
let name = import.js_namespace.as_ref().map(|s| &**s).unwrap_or(item);
|
||||||
@ -1524,10 +1577,10 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match import.js_namespace {
|
Ok(match import.js_namespace {
|
||||||
Some(ref s) => format!("{}.{}", s, item),
|
Some(ref s) => format!("{}.{}", s, item),
|
||||||
None => item.to_string(),
|
None => item.to_string(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::Context;
|
use failure::Error;
|
||||||
use descriptor::{Descriptor, Function};
|
|
||||||
|
|
||||||
use super::{indent, Js2Rust};
|
use descriptor::{Descriptor, Function};
|
||||||
|
use super::{indent, Context, Js2Rust};
|
||||||
|
|
||||||
/// Helper struct for manfuacturing a shim in JS used to translate Rust types to
|
/// Helper struct for manfuacturing a shim in JS used to translate Rust types to
|
||||||
/// JS, then invoking an imported JS function.
|
/// JS, then invoking an imported JS function.
|
||||||
@ -64,15 +64,15 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
|
|
||||||
/// Generates all bindings necessary for the signature in `Function`,
|
/// Generates all bindings necessary for the signature in `Function`,
|
||||||
/// creating necessary argument conversions and return value processing.
|
/// creating necessary argument conversions and return value processing.
|
||||||
pub fn process(&mut self, function: &Function) -> &mut Self {
|
pub fn process(&mut self, function: &Function) -> Result<&mut Self, Error> {
|
||||||
for arg in function.arguments.iter() {
|
for arg in function.arguments.iter() {
|
||||||
self.argument(arg);
|
self.argument(arg)?;
|
||||||
}
|
}
|
||||||
self.ret(&function.ret);
|
self.ret(&function.ret)?;
|
||||||
self
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn argument(&mut self, arg: &Descriptor) {
|
fn argument(&mut self, arg: &Descriptor) -> Result<(), Error> {
|
||||||
let i = self.arg_idx;
|
let i = self.arg_idx;
|
||||||
self.arg_idx += 1;
|
self.arg_idx += 1;
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
|
|
||||||
if let Some(ty) = arg.vector_kind() {
|
if let Some(ty) = arg.vector_kind() {
|
||||||
let f = self.cx.expose_get_vector_from_wasm(ty);
|
let f = self.cx.expose_get_vector_from_wasm(ty);
|
||||||
self.cx.expose_get_global_argument();
|
self.cx.expose_get_global_argument()?;
|
||||||
let next_global = self.global_idx();
|
let next_global = self.global_idx();
|
||||||
self.prelude(&format!("\
|
self.prelude(&format!("\
|
||||||
let len{0} = getGlobalArgument({next_global});\n\
|
let len{0} = getGlobalArgument({next_global});\n\
|
||||||
@ -91,20 +91,20 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
self.prelude(&format!("\
|
self.prelude(&format!("\
|
||||||
wasm.__wbindgen_free(arg{0}, len{0} * {size});\
|
wasm.__wbindgen_free(arg{0}, len{0} * {size});\
|
||||||
", i, size = ty.size()));
|
", i, size = ty.size()));
|
||||||
self.cx.require_internal_export("__wbindgen_free");
|
self.cx.require_internal_export("__wbindgen_free")?;
|
||||||
}
|
}
|
||||||
self.js_arguments.push(format!("v{}", i));
|
self.js_arguments.push(format!("v{}", i));
|
||||||
return
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(class) = arg.rust_struct() {
|
if let Some(class) = arg.rust_struct() {
|
||||||
if arg.is_by_ref() {
|
if arg.is_by_ref() {
|
||||||
panic!("cannot invoke JS functions with custom ref types yet")
|
bail!("cannot invoke JS functions with custom ref types yet")
|
||||||
}
|
}
|
||||||
let assign = format!("let c{0} = {1}.__construct(arg{0});", i, class);
|
let assign = format!("let c{0} = {1}.__construct(arg{0});", i, class);
|
||||||
self.prelude(&assign);
|
self.prelude(&assign);
|
||||||
self.js_arguments.push(format!("c{}", i));
|
self.js_arguments.push(format!("c{}", i));
|
||||||
return
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((f, mutable)) = arg.stack_closure() {
|
if let Some((f, mutable)) = arg.stack_closure() {
|
||||||
@ -120,10 +120,10 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
}
|
}
|
||||||
builder
|
builder
|
||||||
.rust_argument("this.b")
|
.rust_argument("this.b")
|
||||||
.process(f)
|
.process(f)?
|
||||||
.finish("function", "this.f")
|
.finish("function", "this.f")
|
||||||
};
|
};
|
||||||
self.cx.expose_get_global_argument();
|
self.cx.expose_get_global_argument()?;
|
||||||
self.cx.function_table_needed = true;
|
self.cx.function_table_needed = true;
|
||||||
let next_global = self.global_idx();
|
let next_global = self.global_idx();
|
||||||
self.global_idx();
|
self.global_idx();
|
||||||
@ -135,7 +135,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
", i, js = js, next_global = next_global));
|
", i, js = js, next_global = next_global));
|
||||||
self.finally(&format!("cb{0}.a = cb{0}.b = 0;", i));
|
self.finally(&format!("cb{0}.a = cb{0}.b = 0;", i));
|
||||||
self.js_arguments.push(format!("cb{0}.bind(cb{0})", i));
|
self.js_arguments.push(format!("cb{0}.bind(cb{0})", i));
|
||||||
return
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(closure) = arg.ref_closure() {
|
if let Some(closure) = arg.ref_closure() {
|
||||||
@ -151,10 +151,10 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
}
|
}
|
||||||
builder
|
builder
|
||||||
.rust_argument("this.b")
|
.rust_argument("this.b")
|
||||||
.process(&closure.function)
|
.process(&closure.function)?
|
||||||
.finish("function", "this.f")
|
.finish("function", "this.f")
|
||||||
};
|
};
|
||||||
self.cx.expose_get_global_argument();
|
self.cx.expose_get_global_argument()?;
|
||||||
self.cx.expose_uint32_memory();
|
self.cx.expose_uint32_memory();
|
||||||
self.cx.expose_add_heap_object();
|
self.cx.expose_add_heap_object();
|
||||||
self.cx.function_table_needed = true;
|
self.cx.function_table_needed = true;
|
||||||
@ -181,7 +181,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
", i, indent(&reset_idx)));
|
", i, indent(&reset_idx)));
|
||||||
self.cx.expose_get_object();
|
self.cx.expose_get_object();
|
||||||
self.js_arguments.push(format!("getObject(idx{})", i));
|
self.js_arguments.push(format!("getObject(idx{})", i));
|
||||||
return
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let invoc_arg = match *arg {
|
let invoc_arg = match *arg {
|
||||||
@ -195,36 +195,37 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
self.cx.expose_get_object();
|
self.cx.expose_get_object();
|
||||||
format!("getObject(arg{})", i)
|
format!("getObject(arg{})", i)
|
||||||
}
|
}
|
||||||
_ => panic!("unimplemented argument type in imported function: {:?}", arg),
|
_ => bail!("unimplemented argument type in imported function: {:?}", arg),
|
||||||
};
|
};
|
||||||
self.js_arguments.push(invoc_arg);
|
self.js_arguments.push(invoc_arg);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ret(&mut self, ret: &Option<Descriptor>) {
|
fn ret(&mut self, ret: &Option<Descriptor>) -> Result<(), Error> {
|
||||||
let ty = match *ret {
|
let ty = match *ret {
|
||||||
Some(ref t) => t,
|
Some(ref t) => t,
|
||||||
None => {
|
None => {
|
||||||
self.ret_expr = "JS;".to_string();
|
self.ret_expr = "JS;".to_string();
|
||||||
return
|
return Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if ty.is_by_ref() {
|
if ty.is_by_ref() {
|
||||||
panic!("cannot return a reference from JS to Rust")
|
bail!("cannot return a reference from JS to Rust")
|
||||||
}
|
}
|
||||||
if let Some(ty) = ty.vector_kind() {
|
if let Some(ty) = ty.vector_kind() {
|
||||||
let f = self.cx.pass_to_wasm_function(ty);
|
let f = self.cx.pass_to_wasm_function(ty)?;
|
||||||
self.cx.expose_uint32_memory();
|
self.cx.expose_uint32_memory();
|
||||||
self.cx.expose_set_global_argument();
|
self.cx.expose_set_global_argument()?;
|
||||||
self.ret_expr = format!("\
|
self.ret_expr = format!("\
|
||||||
const [retptr, retlen] = {}(JS);\n\
|
const [retptr, retlen] = {}(JS);\n\
|
||||||
setGlobalArgument(retlen, 0);\n\
|
setGlobalArgument(retlen, 0);\n\
|
||||||
return retptr;\n\
|
return retptr;\n\
|
||||||
", f);
|
", f);
|
||||||
return
|
return Ok(())
|
||||||
}
|
}
|
||||||
if ty.is_number() {
|
if ty.is_number() {
|
||||||
self.ret_expr = "return JS;".to_string();
|
self.ret_expr = "return JS;".to_string();
|
||||||
return
|
return Ok(())
|
||||||
}
|
}
|
||||||
self.ret_expr = match *ty {
|
self.ret_expr = match *ty {
|
||||||
Descriptor::Boolean => "return JS ? 1 : 0;".to_string(),
|
Descriptor::Boolean => "return JS ? 1 : 0;".to_string(),
|
||||||
@ -232,8 +233,9 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
self.cx.expose_add_heap_object();
|
self.cx.expose_add_heap_object();
|
||||||
"return addHeapObject(JS);".to_string()
|
"return addHeapObject(JS);".to_string()
|
||||||
}
|
}
|
||||||
_ => panic!("unimplemented return from JS to Rust: {:?}", ty),
|
_ => bail!("unimplemented return from JS to Rust: {:?}", ty),
|
||||||
}
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(&self, invoc: &str) -> String {
|
pub fn finish(&self, invoc: &str) -> String {
|
||||||
|
@ -3,6 +3,8 @@ extern crate wasm_bindgen_shared as shared;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate wasm_gc;
|
extern crate wasm_gc;
|
||||||
extern crate wasmi;
|
extern crate wasmi;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate failure;
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -10,6 +12,7 @@ use std::fs::File;
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use failure::{Error, ResultExt};
|
||||||
use parity_wasm::elements::*;
|
use parity_wasm::elements::*;
|
||||||
|
|
||||||
mod js;
|
mod js;
|
||||||
@ -27,15 +30,6 @@ pub struct Bindgen {
|
|||||||
demangle: bool,
|
demangle: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Error(String);
|
|
||||||
|
|
||||||
impl<E: std::error::Error> From<E> for Error {
|
|
||||||
fn from(e: E) -> Error {
|
|
||||||
Error(e.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bindgen {
|
impl Bindgen {
|
||||||
pub fn new() -> Bindgen {
|
pub fn new() -> Bindgen {
|
||||||
Bindgen {
|
Bindgen {
|
||||||
@ -97,11 +91,13 @@ impl Bindgen {
|
|||||||
fn _generate(&mut self, out_dir: &Path) -> Result<(), Error> {
|
fn _generate(&mut self, out_dir: &Path) -> Result<(), Error> {
|
||||||
let input = match self.path {
|
let input = match self.path {
|
||||||
Some(ref path) => path,
|
Some(ref path) => path,
|
||||||
None => panic!("must have a path input for now"),
|
None => bail!("must have a path input for now"),
|
||||||
};
|
};
|
||||||
let stem = input.file_stem().unwrap().to_str().unwrap();
|
let stem = input.file_stem().unwrap().to_str().unwrap();
|
||||||
let mut module = parity_wasm::deserialize_file(input)?;
|
let mut module = parity_wasm::deserialize_file(input)
|
||||||
let programs = extract_programs(&mut module);
|
.with_context(|_| "failed to parse input file as wasm")?;
|
||||||
|
let programs = extract_programs(&mut module)
|
||||||
|
.with_context(|_| "failed to extract wasm-bindgen custom sections")?;
|
||||||
|
|
||||||
// Here we're actually instantiating the module we've parsed above for
|
// Here we're actually instantiating the module we've parsed above for
|
||||||
// execution. Why, you might be asking, are we executing wasm code? A
|
// execution. Why, you might be asking, are we executing wasm code? A
|
||||||
@ -116,8 +112,10 @@ impl Bindgen {
|
|||||||
// This means that whenever we encounter an import or export we'll
|
// This means that whenever we encounter an import or export we'll
|
||||||
// execute a shim function which informs us about its type so we can
|
// execute a shim function which informs us about its type so we can
|
||||||
// then generate the appropriate bindings.
|
// then generate the appropriate bindings.
|
||||||
let instance = wasmi::Module::from_parity_wasm_module(module.clone())?;
|
let instance = wasmi::Module::from_parity_wasm_module(module.clone())
|
||||||
let instance = wasmi::ModuleInstance::new(&instance, &MyResolver)?;
|
.with_context(|_| "failed to create wasmi module")?;
|
||||||
|
let instance = wasmi::ModuleInstance::new(&instance, &MyResolver)
|
||||||
|
.with_context(|_| "failed to instantiate wasm module")?;
|
||||||
let instance = instance.not_started_instance();
|
let instance = instance.not_started_instance();
|
||||||
|
|
||||||
let (js, ts) = {
|
let (js, ts) = {
|
||||||
@ -146,19 +144,21 @@ impl Bindgen {
|
|||||||
js::SubContext {
|
js::SubContext {
|
||||||
program,
|
program,
|
||||||
cx: &mut cx,
|
cx: &mut cx,
|
||||||
}.generate();
|
}.generate()?;
|
||||||
}
|
}
|
||||||
cx.finalize(stem)
|
cx.finalize(stem)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let js_path = out_dir.join(stem).with_extension("js");
|
let js_path = out_dir.join(stem).with_extension("js");
|
||||||
File::create(&js_path).unwrap()
|
File::create(&js_path)
|
||||||
.write_all(js.as_bytes()).unwrap();
|
.and_then(|mut f| f.write_all(js.as_bytes()))
|
||||||
|
.with_context(|_| format!("failed to write `{}`", js_path.display()))?;
|
||||||
|
|
||||||
if self.typescript {
|
if self.typescript {
|
||||||
let ts_path = out_dir.join(stem).with_extension("d.ts");
|
let ts_path = out_dir.join(stem).with_extension("d.ts");
|
||||||
File::create(&ts_path).unwrap()
|
File::create(&ts_path)
|
||||||
.write_all(ts.as_bytes()).unwrap();
|
.and_then(|mut f| f.write_all(ts.as_bytes()))
|
||||||
|
.with_context(|_| format!("failed to write `{}`", ts_path.display()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let wasm_path = out_dir.join(format!("{}_bg", stem)).with_extension("wasm");
|
let wasm_path = out_dir.join(format!("{}_bg", stem)).with_extension("wasm");
|
||||||
@ -166,13 +166,15 @@ impl Bindgen {
|
|||||||
if self.nodejs {
|
if self.nodejs {
|
||||||
let js_path = wasm_path.with_extension("js");
|
let js_path = wasm_path.with_extension("js");
|
||||||
let shim = self.generate_node_wasm_import(&module, &wasm_path);
|
let shim = self.generate_node_wasm_import(&module, &wasm_path);
|
||||||
File::create(&js_path)?.write_all(shim.as_bytes())?;
|
File::create(&js_path)
|
||||||
|
.and_then(|mut f| f.write_all(shim.as_bytes()))
|
||||||
|
.with_context(|_| format!("failed to write `{}`", js_path.display()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let wasm_bytes = parity_wasm::serialize(module).map_err(|e| {
|
let wasm_bytes = parity_wasm::serialize(module)?;
|
||||||
Error(format!("{:?}", e))
|
File::create(&wasm_path)
|
||||||
})?;
|
.and_then(|mut f| f.write_all(&wasm_bytes))
|
||||||
File::create(&wasm_path)?.write_all(&wasm_bytes)?;
|
.with_context(|_| format!("failed to write `{}`", wasm_path.display()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,18 +204,20 @@ impl Bindgen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_programs(module: &mut Module) -> Vec<shared::Program> {
|
fn extract_programs(module: &mut Module) -> Result<Vec<shared::Program>, Error> {
|
||||||
let version = shared::version();
|
let version = shared::version();
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
|
let mut to_remove = Vec::new();
|
||||||
|
|
||||||
module.sections_mut().retain(|s| {
|
for (i, s) in module.sections().iter().enumerate() {
|
||||||
let custom = match *s {
|
let custom = match *s {
|
||||||
Section::Custom(ref s) => s,
|
Section::Custom(ref s) => s,
|
||||||
_ => return true,
|
_ => continue,
|
||||||
};
|
};
|
||||||
if custom.name() != "__wasm_bindgen_unstable" {
|
if custom.name() != "__wasm_bindgen_unstable" {
|
||||||
return true
|
continue
|
||||||
}
|
}
|
||||||
|
to_remove.push(i);
|
||||||
|
|
||||||
let mut payload = custom.payload();
|
let mut payload = custom.payload();
|
||||||
while payload.len() > 0 {
|
while payload.len() > 0 {
|
||||||
@ -227,11 +231,11 @@ fn extract_programs(module: &mut Module) -> Vec<shared::Program> {
|
|||||||
let p: shared::ProgramOnlySchema = match serde_json::from_slice(&a) {
|
let p: shared::ProgramOnlySchema = match serde_json::from_slice(&a) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("failed to decode what looked like wasm-bindgen data: {}", e)
|
bail!("failed to decode what looked like wasm-bindgen data: {}", e)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if p.schema_version != shared::SCHEMA_VERSION {
|
if p.schema_version != shared::SCHEMA_VERSION {
|
||||||
panic!("
|
bail!("
|
||||||
|
|
||||||
it looks like the Rust project used to create this wasm file was linked against
|
it looks like the Rust project used to create this wasm file was linked against
|
||||||
a different version of wasm-bindgen than this binary:
|
a different version of wasm-bindgen than this binary:
|
||||||
@ -258,15 +262,17 @@ to open an issue at https://github.com/alexcrichton/wasm-bindgen/issues!
|
|||||||
let p: shared::Program = match serde_json::from_slice(&a) {
|
let p: shared::Program = match serde_json::from_slice(&a) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("failed to decode what looked like wasm-bindgen data: {}", e)
|
bail!("failed to decode what looked like wasm-bindgen data: {}", e)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ret.push(p);
|
ret.push(p);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
false
|
for i in to_remove.into_iter().rev() {
|
||||||
});
|
module.sections_mut().remove(i);
|
||||||
return ret
|
}
|
||||||
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MyResolver;
|
struct MyResolver;
|
||||||
|
@ -3,8 +3,7 @@ extern crate base64;
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use parity_wasm::elements::*;
|
use parity_wasm::elements::*;
|
||||||
|
use failure::Error;
|
||||||
use super::Error;
|
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
base64: bool,
|
base64: bool,
|
||||||
@ -37,11 +36,9 @@ impl Config {
|
|||||||
|
|
||||||
pub fn generate(&mut self, wasm: &[u8]) -> Result<Output, Error> {
|
pub fn generate(&mut self, wasm: &[u8]) -> Result<Output, Error> {
|
||||||
if !self.base64 && !self.fetch_path.is_some() {
|
if !self.base64 && !self.fetch_path.is_some() {
|
||||||
panic!("the option --base64 or --fetch is required");
|
bail!("the option --base64 or --fetch is required");
|
||||||
}
|
}
|
||||||
let module = deserialize_buffer(wasm).map_err(|e| {
|
let module = deserialize_buffer(wasm)?;
|
||||||
::Error(format!("{:?}", e))
|
|
||||||
})?;
|
|
||||||
Ok(Output {
|
Ok(Output {
|
||||||
module,
|
module,
|
||||||
base64: self.base64,
|
base64: self.base64,
|
||||||
@ -110,7 +107,7 @@ impl Output {
|
|||||||
return exports
|
return exports
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn js(self) -> String {
|
pub fn js(self) -> Result<String, Error> {
|
||||||
let mut js_imports = String::new();
|
let mut js_imports = String::new();
|
||||||
let mut exports = String::new();
|
let mut exports = String::new();
|
||||||
let mut imports = String::new();
|
let mut imports = String::new();
|
||||||
@ -122,13 +119,13 @@ impl Output {
|
|||||||
match *entry.external() {
|
match *entry.external() {
|
||||||
External::Function(_) => {}
|
External::Function(_) => {}
|
||||||
External::Table(_) => {
|
External::Table(_) => {
|
||||||
panic!("wasm imports a table which isn't supported yet");
|
bail!("wasm imports a table which isn't supported yet");
|
||||||
}
|
}
|
||||||
External::Memory(_) => {
|
External::Memory(_) => {
|
||||||
panic!("wasm imports memory which isn't supported yet");
|
bail!("wasm imports memory which isn't supported yet");
|
||||||
}
|
}
|
||||||
External::Global(_) => {
|
External::Global(_) => {
|
||||||
panic!("wasm imports globals which aren't supported yet");
|
bail!("wasm imports globals which aren't supported yet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,9 +218,9 @@ impl Output {
|
|||||||
.then(bytes => {inst})", path = path, inst = inst)
|
.then(bytes => {inst})", path = path, inst = inst)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
panic!("the option --base64 or --fetch is required");
|
bail!("the option --base64 or --fetch is required");
|
||||||
};
|
};
|
||||||
format!("
|
Ok(format!("
|
||||||
{js_imports}
|
{js_imports}
|
||||||
let wasm;
|
let wasm;
|
||||||
{bytes}
|
{bytes}
|
||||||
@ -236,6 +233,6 @@ impl Output {
|
|||||||
js_imports = js_imports,
|
js_imports = js_imports,
|
||||||
exports = exports,
|
exports = exports,
|
||||||
mem_export = if export_mem { "export let memory;" } else { "" },
|
mem_export = if export_mem { "export let memory;" } else { "" },
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ information see https://github.com/alexcrichton/wasm-bindgen.
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
docopt = "0.8"
|
docopt = "0.8"
|
||||||
|
failure = "0.1"
|
||||||
parity-wasm = "0.27"
|
parity-wasm = "0.27"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
@ -3,11 +3,15 @@ extern crate wasm_bindgen_cli_support;
|
|||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
extern crate wasm_bindgen_shared;
|
extern crate wasm_bindgen_shared;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate failure;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
use wasm_bindgen_cli_support::Bindgen;
|
use wasm_bindgen_cli_support::Bindgen;
|
||||||
|
use failure::Error;
|
||||||
|
|
||||||
const USAGE: &'static str = "
|
const USAGE: &'static str = "
|
||||||
Generating JS bindings for a wasm file
|
Generating JS bindings for a wasm file
|
||||||
@ -53,14 +57,25 @@ fn main() {
|
|||||||
println!("wasm-bindgen {}", wasm_bindgen_shared::version());
|
println!("wasm-bindgen {}", wasm_bindgen_shared::version());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let err = match rmain(&args) {
|
||||||
|
Ok(()) => return,
|
||||||
|
Err(e) => e,
|
||||||
|
};
|
||||||
|
println!("error: {}", err);
|
||||||
|
for cause in err.causes().skip(1) {
|
||||||
|
println!("\tcaused by: {}", cause);
|
||||||
|
}
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rmain(args: &Args) -> Result<(), Error> {
|
||||||
let input = match args.arg_input {
|
let input = match args.arg_input {
|
||||||
Some(s) => s,
|
Some(ref s) => s,
|
||||||
None => panic!("input file expected"),
|
None => bail!("input file expected"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut b = Bindgen::new();
|
let mut b = Bindgen::new();
|
||||||
b.input_path(&input)
|
b.input_path(input)
|
||||||
.nodejs(args.flag_nodejs)
|
.nodejs(args.flag_nodejs)
|
||||||
.browser(args.flag_browser)
|
.browser(args.flag_browser)
|
||||||
.no_modules(args.flag_no_modules)
|
.no_modules(args.flag_no_modules)
|
||||||
@ -73,8 +88,8 @@ fn main() {
|
|||||||
|
|
||||||
let out_dir = match args.flag_out_dir {
|
let out_dir = match args.flag_out_dir {
|
||||||
Some(ref p) => p,
|
Some(ref p) => p,
|
||||||
None => panic!("the `--out-dir` argument is now required"),
|
None => bail!("the `--out-dir` argument is now required"),
|
||||||
};
|
};
|
||||||
|
|
||||||
b.generate(out_dir).expect("failed to generate bindings");
|
b.generate(out_dir)
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,16 @@ extern crate serde_derive;
|
|||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
extern crate parity_wasm;
|
extern crate parity_wasm;
|
||||||
extern crate wasm_bindgen_cli_support;
|
extern crate wasm_bindgen_cli_support;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate failure;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Write, Read};
|
use std::io::{Write, Read};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
|
use failure::{Error, ResultExt};
|
||||||
|
|
||||||
const USAGE: &'static str = "
|
const USAGE: &'static str = "
|
||||||
Converts a wasm file to an ES6 JS module
|
Converts a wasm file to an ES6 JS module
|
||||||
@ -42,38 +46,56 @@ fn main() {
|
|||||||
let args: Args = Docopt::new(USAGE)
|
let args: Args = Docopt::new(USAGE)
|
||||||
.and_then(|d| d.deserialize())
|
.and_then(|d| d.deserialize())
|
||||||
.unwrap_or_else(|e| e.exit());
|
.unwrap_or_else(|e| e.exit());
|
||||||
|
let err = match rmain(&args) {
|
||||||
|
Ok(()) => return,
|
||||||
|
Err(e) => e,
|
||||||
|
};
|
||||||
|
println!("error: {}", err);
|
||||||
|
for cause in err.causes().skip(1) {
|
||||||
|
println!("\tcaused by: {}", cause);
|
||||||
|
}
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rmain(args: &Args) -> Result<(), Error> {
|
||||||
if !args.flag_base64 && !args.flag_fetch.is_some() {
|
if !args.flag_base64 && !args.flag_fetch.is_some() {
|
||||||
panic!("unfortunately only works right now with base64 or fetch");
|
bail!("unfortunately only works right now with base64 or fetch");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut wasm = Vec::new();
|
let mut wasm = Vec::new();
|
||||||
File::open(&args.arg_input).expect("failed to open input")
|
File::open(&args.arg_input)
|
||||||
.read_to_end(&mut wasm).expect("failed to read input");
|
.and_then(|mut f| f.read_to_end(&mut wasm))
|
||||||
|
.with_context(|_| format!("failed to read `{}`", args.arg_input.display()))?;
|
||||||
|
|
||||||
let object = wasm_bindgen_cli_support::wasm2es6js::Config::new()
|
let object = wasm_bindgen_cli_support::wasm2es6js::Config::new()
|
||||||
.base64(args.flag_base64)
|
.base64(args.flag_base64)
|
||||||
.fetch(args.flag_fetch)
|
.fetch(args.flag_fetch.clone())
|
||||||
.generate(&wasm)
|
.generate(&wasm)?;
|
||||||
.expect("failed to parse wasm");
|
|
||||||
|
|
||||||
if args.flag_typescript {
|
if args.flag_typescript {
|
||||||
if let Some(ref p) = args.flag_output {
|
if let Some(ref p) = args.flag_output {
|
||||||
let dst = p.with_extension("d.ts");
|
let dst = p.with_extension("d.ts");
|
||||||
File::create(dst).expect("failed to create output")
|
let ts = object.typescript();
|
||||||
.write_all(object.typescript().as_bytes()).expect("failed to write output");
|
File::create(&dst)
|
||||||
|
.and_then(|mut f| f.write_all(ts.as_bytes()))
|
||||||
|
.with_context(|_| {
|
||||||
|
format!("failed to write `{}`", dst.display())
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let js = object.js();
|
let js = object.js()?;
|
||||||
|
|
||||||
match args.flag_output {
|
match args.flag_output {
|
||||||
Some(ref p) => {
|
Some(ref p) => {
|
||||||
File::create(p).expect("failed to create output")
|
File::create(p)
|
||||||
.write_all(js.as_bytes()).expect("failed to write output");
|
.and_then(|mut f| f.write_all(js.as_bytes()))
|
||||||
|
.with_context(|_| format!("failed to write `{}`", p.display()))?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
println!("{}", js);
|
println!("{}", js);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user