Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better output from impl Debug for JsValue. #1161

Merged
merged 14 commits into from
Jan 18, 2019

Conversation

derekdreery
Copy link
Contributor

We can use JSON.stringify to get a better debug representation of a value. It's slow, but I think there's an acceptance that Debug (unlike maybe Display) is allowed to be slow to write better strings, given that it's used mostly before deployment.

There's also a new method for testing whether something is an array in javascript. I can remove this if you don't think it's useful.

@derekdreery
Copy link
Contributor Author

This should have some tests I think (it doesn't yet).

@alexcrichton
Copy link
Contributor

Thanks for this!

Reading this over, I wonder if we perhaps want to actually just move the entire Debug implementation into JS? The code size footprint in Rust is actually pretty large we've seen in the past with float parsing and whatnot, and if we're hopping back and forth to JS to test types and whatnot it may actually just be best to have stringification happen directly in JS.

@derekdreery
Copy link
Contributor Author

Good idea! I'll experiment.

@derekdreery
Copy link
Contributor Author

I've done an implementation in JS. See what you think.

There's still a TODO around no-std. This patch actually regresses to doing nothing. Can we do something to get the string in the case that we don't have an allocator?

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this approach!

src/lib.rs Outdated
@@ -298,11 +298,32 @@ impl JsValue {
unsafe { __wbindgen_is_object(self.idx) == 1 }
}

/// Tests whether `Array.isArray(self)`.
#[inline]
pub fn is_array(&self) -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be unused? If so, then we should remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah if it were to be included it should be a separate PR. I'll remove.

Ok(String::from(
"
function(i, len_ptr) {
const debug_str = val => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to come up with something that supported as rich of debug string output as this but was a little more terse. Not sure I really ended up on an improvement over what you have here, but for posterity:

function debug(val) {
  switch(typeof val) {
    case "undefined":
    case "number":
    case "boolean":
    case "symbol":
      return String(val);
    case "function":
      return `Function(${val.name || ""})`;
    case "object":
      if (val === null) {
        return "null";
      }
      const s = Object.prototype.toString.call(val);
      if (s === "[object Object]" || s === "[object Array]") {
        try {
          return JSON.stringify(val);
        } catch (_) {}
      }
      return s;
    default:
      return Object.prototype.toString.call(val);
  }
}

Copy link
Contributor Author

@derekdreery derekdreery Jan 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool. I did think about doing a big switch. If JSON.stringify can throw, I should catch it and just fall through like you do. If we can capture the function name that would be cool also. I'll try to merge the 2 impls.

Also since I'm assuming there's no stability guarantees on the output here we can always refine later.

  • get name of the function if possible
  • if JSON.stringify can throw, catch and ignore any exceptions.
  • get toString from Object.prototype

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If JSON.stringify can throw

json-lol

This is also why I did Object.prototype.toString.call(val) rather than val.toString() or String(val) etc.

@fitzgen
Copy link
Member

fitzgen commented Jan 11, 2019

There's still a TODO around no-std. This patch actually regresses to doing nothing. Can we do something to get the string in the case that we don't have an allocator?

I don't think there is an easy way, unfortunately.

@derekdreery
Copy link
Contributor Author

I don't think there is an easy way, unfortunately.

I think I probably need to restore the old impl then for the no_std case.

@alexcrichton
Copy link
Contributor

I think it's fine to in general not worry much about the no_std use case, I don't think that it's really operational at all and likely won't make its way to the next major release of wasm-bindgen. (I personally think I was mistaken to add it originally!)

@fitzgen
Copy link
Member

fitzgen commented Jan 11, 2019

I think it's fine to in general not worry much about the no_std use case, I don't think that it's really operational at all and likely won't make its way to the next major release of wasm-bindgen. (I personally think I was mistaken to add it originally!)

Agreed, FWIW.

@derekdreery
Copy link
Contributor Author

I've added suggestings from @fitzgen, and also rebased.

@derekdreery
Copy link
Contributor Author

I think this is ready for review now. I've tried to cover all the cases in the tests. I found quite a few problems, which I guess is why tests!!!!

@derekdreery
Copy link
Contributor Author

Not sure where the failure's from.

@fitzgen
Copy link
Member

fitzgen commented Jan 14, 2019

https://travis-ci.com/rustwasm/wasm-bindgen/jobs/169969977#L894-L906

---- wasm::api::debug_output output ----
    JS exception that was thrown:
        TypeError: getObject(...).values is not a function
            at module.exports.__wbg_values_c7388d2dffc70125 (/home/travis/build/rustwasm/wasm-bindgen/target/wasm32-unknown-unknown/wbg-tmp/wasm-bindgen-test.js:4348:42)
            at js_sys::Array::values::h413e65c06a2161cc (wasm-function[8094]:101)
            at wasm::api::debug_output::h53891ce08362a31e (wasm-function[2663]:96)
            at core::ops::function::FnOnce::call_once::h155aa4ffc67eec53 (wasm-function[1035]:22)
            at wasm_bindgen_test::__rt::Context::execute_sync::_$u7b$$u7b$closure$u7d$$u7d$::h3886c0814e7f4942 (wasm-function[3976]:22)
            at _$LT$futures..future..lazy..Lazy$LT$F$C$$u20$R$GT$$GT$::get::hc1c1b592d7026e96 (wasm-function[654]:395)
            at _$LT$futures..future..lazy..Lazy$LT$F$C$$u20$R$GT$$u20$as$u20$futures..future..Future$GT$::poll::hc9d74cbdf88e301e (wasm-function[859]:38)
            at _$LT$wasm_bindgen_test..__rt..TestFuture$LT$F$GT$$u20$as$u20$futures..future..Future$GT$::poll::_$u7b$$u7b$closure$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::h89214d033d0eec01 (wasm-function[4309]:71)
            at wasm_bindgen::convert::closures::invoke0_mut::h34f83a9aa7fb5334 (wasm-function[7341]:166)
            at Function.cbarg0 (/home/travis/build/rustwasm/wasm-bindgen/target/wasm32-unknown-unknown/wbg-tmp/wasm-bindgen-test.js:4275:25)

I believe that node doesn't support Array.prototype.values yet, so maybe that is what is going on here.

@derekdreery derekdreery changed the title Use JSON serialization to get better debug printouts. Better output from impl Debug for JsValue. Jan 16, 2019
Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a couple nitpicks below about the __wbg_is_array stuff that still hasn't gotten removed.

@@ -299,6 +299,18 @@ impl<'a> Context<'a> {
))
})?;

self.bind("__wbindgen_is_array", &|me| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: remove this

src/lib.rs Outdated
@@ -474,9 +489,11 @@ externs! {
fn __wbindgen_symbol_new(ptr: *const u8, len: usize) -> u32;
fn __wbindgen_is_symbol(idx: u32) -> u32;
fn __wbindgen_is_object(idx: u32) -> u32;
fn __wbindgen_is_array(idx: u32) -> u32;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: remove this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep sorry missed this last time.

@alexcrichton alexcrichton merged commit ba732a8 into rustwasm:master Jan 18, 2019
@derekdreery derekdreery deleted the debug_output branch January 18, 2019 11:55
@fitzgen fitzgen added the TWiRaWA Nominate this PR for inclusion in the next issue of This Week in Rust and WebAssembly label Feb 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
TWiRaWA Nominate this PR for inclusion in the next issue of This Week in Rust and WebAssembly
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants