mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-11 06:36:05 +00:00
Merge pull request #1161 from derekdreery/debug_output
Better output from `impl Debug for JsValue`.
This commit is contained in:
commit
ba732a8a72
@ -6,7 +6,7 @@ INSTALL_NODE_VIA_NVM: &INSTALL_NODE_VIA_NVM
|
|||||||
rustup target add wasm32-unknown-unknown
|
rustup target add wasm32-unknown-unknown
|
||||||
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
|
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
|
||||||
source ~/.nvm/nvm.sh
|
source ~/.nvm/nvm.sh
|
||||||
nvm install v10.5
|
nvm install v10.9
|
||||||
|
|
||||||
INSTALL_GECKODRIVER: &INSTALL_GECKODRIVER
|
INSTALL_GECKODRIVER: &INSTALL_GECKODRIVER
|
||||||
|
|
|
|
||||||
|
@ -338,6 +338,88 @@ impl<'a> Context<'a> {
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
self.bind("__wbindgen_debug_string", &|me| {
|
||||||
|
me.expose_pass_string_to_wasm()?;
|
||||||
|
me.expose_get_object();
|
||||||
|
me.expose_uint32_memory();
|
||||||
|
Ok(String::from(
|
||||||
|
"
|
||||||
|
function(i, len_ptr) {
|
||||||
|
const toString = Object.prototype.toString;
|
||||||
|
const debug_str = val => {
|
||||||
|
// primitive types
|
||||||
|
const type = typeof val;
|
||||||
|
if (type == 'number' || type == 'boolean' || val == null) {
|
||||||
|
return `${val}`;
|
||||||
|
}
|
||||||
|
if (type == 'string') {
|
||||||
|
return `\"${val}\"`;
|
||||||
|
}
|
||||||
|
if (type == 'symbol') {
|
||||||
|
const description = val.description;
|
||||||
|
if (description == null) {
|
||||||
|
return 'Symbol';
|
||||||
|
} else {
|
||||||
|
return `Symbol(${description})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type == 'function') {
|
||||||
|
const name = val.name;
|
||||||
|
if (typeof name == 'string' && name.length > 0) {
|
||||||
|
return `Function(${name})`;
|
||||||
|
} else {
|
||||||
|
return 'Function';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// objects
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
const length = val.length;
|
||||||
|
let debug = '[';
|
||||||
|
if (length > 0) {
|
||||||
|
debug += debug_str(val[0]);
|
||||||
|
}
|
||||||
|
for(let i = 1; i < length; i++) {
|
||||||
|
debug += ', ' + debug_str(val[i]);
|
||||||
|
}
|
||||||
|
debug += ']';
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
// Test for built-in
|
||||||
|
const builtInMatches = /\\[object ([^\\]]+)\\]/.exec(toString.call(val));
|
||||||
|
let className;
|
||||||
|
if (builtInMatches.length > 1) {
|
||||||
|
className = builtInMatches[1];
|
||||||
|
} else {
|
||||||
|
// Failed to match the standard '[object ClassName]'
|
||||||
|
return toString.call(val);
|
||||||
|
}
|
||||||
|
if (className == 'Object') {
|
||||||
|
// we're a user defined class or Object
|
||||||
|
// JSON.stringify avoids problems with cycles, and is generally much
|
||||||
|
// easier than looping through ownProperties of `val`.
|
||||||
|
try {
|
||||||
|
return 'Object(' + JSON.stringify(val) + ')';
|
||||||
|
} catch (_) {
|
||||||
|
return 'Object';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// errors
|
||||||
|
if (val instanceof Error) {
|
||||||
|
return `${val.name}: ${val.message}\n${val.stack}`;
|
||||||
|
}
|
||||||
|
// TODO we could test for more things here, like `Set`s and `Map`s.
|
||||||
|
return className;
|
||||||
|
};
|
||||||
|
const val = getObject(i);
|
||||||
|
const debug = debug_str(val);
|
||||||
|
const ptr = passStringToWasm(debug);
|
||||||
|
getUint32Memory()[len_ptr / 4] = WASM_VECTOR_LEN;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
",
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
self.bind("__wbindgen_cb_drop", &|me| {
|
self.bind("__wbindgen_cb_drop", &|me| {
|
||||||
me.expose_drop_ref();
|
me.expose_drop_ref();
|
||||||
Ok(String::from(
|
Ok(String::from(
|
||||||
|
47
src/lib.rs
47
src/lib.rs
@ -303,6 +303,21 @@ impl JsValue {
|
|||||||
pub fn is_function(&self) -> bool {
|
pub fn is_function(&self) -> bool {
|
||||||
unsafe { __wbindgen_is_function(self.idx) == 1 }
|
unsafe { __wbindgen_is_function(self.idx) == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a string representation of the JavaScript object for debugging
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
fn as_debug_string(&self) -> String {
|
||||||
|
unsafe {
|
||||||
|
let mut len = 0;
|
||||||
|
let ptr = __wbindgen_debug_string(self.idx, &mut len);
|
||||||
|
if ptr.is_null() {
|
||||||
|
unreachable!("`__wbindgen_debug_string` must return a valid string")
|
||||||
|
} else {
|
||||||
|
let data = Vec::from_raw_parts(ptr, len, len);
|
||||||
|
String::from_utf8_unchecked(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for JsValue {
|
impl PartialEq for JsValue {
|
||||||
@ -477,6 +492,7 @@ externs! {
|
|||||||
fn __wbindgen_is_function(idx: u32) -> u32;
|
fn __wbindgen_is_function(idx: u32) -> u32;
|
||||||
fn __wbindgen_is_string(idx: u32) -> u32;
|
fn __wbindgen_is_string(idx: u32) -> u32;
|
||||||
fn __wbindgen_string_get(idx: u32, len: *mut usize) -> *mut u8;
|
fn __wbindgen_string_get(idx: u32, len: *mut usize) -> *mut u8;
|
||||||
|
fn __wbindgen_debug_string(idx: u32, len: *mut usize) -> *mut u8;
|
||||||
fn __wbindgen_throw(a: *const u8, b: usize) -> !;
|
fn __wbindgen_throw(a: *const u8, b: usize) -> !;
|
||||||
fn __wbindgen_rethrow(a: u32) -> !;
|
fn __wbindgen_rethrow(a: u32) -> !;
|
||||||
|
|
||||||
@ -503,30 +519,17 @@ impl Clone for JsValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
impl fmt::Debug for JsValue {
|
impl fmt::Debug for JsValue {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if let Some(n) = self.as_f64() {
|
write!(f, "JsValue({})", self.as_debug_string())
|
||||||
return n.fmt(f);
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "std")]
|
|
||||||
{
|
#[cfg(not(feature = "std"))]
|
||||||
if let Some(n) = self.as_string() {
|
impl fmt::Debug for JsValue {
|
||||||
return n.fmt(f);
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
}
|
f.write_str("JsValue")
|
||||||
}
|
|
||||||
if let Some(n) = self.as_bool() {
|
|
||||||
return n.fmt(f);
|
|
||||||
}
|
|
||||||
if self.is_null() {
|
|
||||||
return fmt::Display::fmt("null", f);
|
|
||||||
}
|
|
||||||
if self.is_undefined() {
|
|
||||||
return fmt::Display::fmt("undefined", f);
|
|
||||||
}
|
|
||||||
if self.is_symbol() {
|
|
||||||
return fmt::Display::fmt("Symbol(..)", f);
|
|
||||||
}
|
|
||||||
fmt::Display::fmt("[object]", f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,3 +41,17 @@ exports.js_eq_works = () => {
|
|||||||
assert.strictEqual(wasm.eq_test(x, x), true);
|
assert.strictEqual(wasm.eq_test(x, x), true);
|
||||||
assert.strictEqual(wasm.eq_test1(x), true);
|
assert.strictEqual(wasm.eq_test1(x), true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.debug_values = () => ([
|
||||||
|
null,
|
||||||
|
undefined,
|
||||||
|
0,
|
||||||
|
1.0,
|
||||||
|
true,
|
||||||
|
[1,2,3],
|
||||||
|
"string",
|
||||||
|
{test: "object"},
|
||||||
|
[1.0, [2.0, 3.0]],
|
||||||
|
() => (null),
|
||||||
|
new Set(),
|
||||||
|
]);
|
||||||
|
@ -8,6 +8,7 @@ extern "C" {
|
|||||||
fn js_works();
|
fn js_works();
|
||||||
fn js_eq_works();
|
fn js_eq_works();
|
||||||
fn assert_null(v: JsValue);
|
fn assert_null(v: JsValue);
|
||||||
|
fn debug_values() -> JsValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
@ -71,7 +72,7 @@ pub fn api_get_false() -> JsValue {
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn api_test_bool(a: &JsValue, b: &JsValue, c: &JsValue) {
|
pub fn api_test_bool(a: &JsValue, b: &JsValue, c: &JsValue) {
|
||||||
assert_eq!(a.as_bool(), Some(true));
|
assert_eq!(a.as_bool(), Some(true));
|
||||||
assert_eq!(format!("{:?}", a), "true");
|
assert_eq!(format!("{:?}", a), "JsValue(true)");
|
||||||
assert_eq!(b.as_bool(), Some(false));
|
assert_eq!(b.as_bool(), Some(false));
|
||||||
assert_eq!(c.as_bool(), None);
|
assert_eq!(c.as_bool(), None);
|
||||||
}
|
}
|
||||||
@ -80,7 +81,7 @@ pub fn api_test_bool(a: &JsValue, b: &JsValue, c: &JsValue) {
|
|||||||
pub fn api_mk_symbol() -> JsValue {
|
pub fn api_mk_symbol() -> JsValue {
|
||||||
let a = JsValue::symbol(None);
|
let a = JsValue::symbol(None);
|
||||||
assert!(a.is_symbol());
|
assert!(a.is_symbol());
|
||||||
assert_eq!(format!("{:?}", a), "Symbol(..)");
|
assert_eq!(format!("{:?}", a), "JsValue(Symbol)");
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +101,7 @@ pub fn api_assert_symbols(a: &JsValue, b: &JsValue) {
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn api_acquire_string(a: &JsValue, b: &JsValue) {
|
pub fn api_acquire_string(a: &JsValue, b: &JsValue) {
|
||||||
assert_eq!(a.as_string().unwrap(), "foo");
|
assert_eq!(a.as_string().unwrap(), "foo");
|
||||||
assert_eq!(format!("{:?}", a), "\"foo\"");
|
assert_eq!(format!("{:?}", a), "JsValue(\"foo\")");
|
||||||
assert_eq!(b.as_string(), None);
|
assert_eq!(b.as_string(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,3 +146,24 @@ fn memory_accessor_appears_to_work() {
|
|||||||
.for_each(&mut |val, _, _| v.push(val));
|
.for_each(&mut |val, _, _| v.push(val));
|
||||||
assert_eq!(v, [3, 0, 0, 0]);
|
assert_eq!(v, [3, 0, 0, 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn debug_output() {
|
||||||
|
let test_iter = debug_values().dyn_into::<js_sys::Array>().unwrap().values().into_iter();
|
||||||
|
let expecteds = vec![
|
||||||
|
"JsValue(null)",
|
||||||
|
"JsValue(undefined)",
|
||||||
|
"JsValue(0)",
|
||||||
|
"JsValue(1)",
|
||||||
|
"JsValue(true)",
|
||||||
|
"JsValue([1, 2, 3])",
|
||||||
|
"JsValue(\"string\")",
|
||||||
|
"JsValue(Object({\"test\":\"object\"}))",
|
||||||
|
"JsValue([1, [2, 3]])",
|
||||||
|
"JsValue(Function)",
|
||||||
|
"JsValue(Set)",
|
||||||
|
];
|
||||||
|
for (test, expected) in test_iter.zip(expecteds) {
|
||||||
|
assert_eq!(format!("{:?}", test.unwrap()), expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user