DelSkayn / rquickjs

High level bindings to the quickjs javascript engine
MIT License
504 stars 63 forks source link

rquickjs::Error::Exception should preserve the original value #138

Closed RReverser closed 1 year ago

RReverser commented 1 year ago

In JavaScript, while uncommon, it's possible to throw arbitrary values, not just Error objects and some libraries actually make use of it.

Right now rquickjs doesn't allow to retrieve this non-Error value and fails with conversion errors instead, as the Exception variant can't represent anything but error objects:

Exception {
    message: StdString,
    file: StdString,
    line: i32,
    stack: StdString,
},

Example:

fn main() {
    let runtime = rquickjs::Runtime::new().unwrap();
    let context = rquickjs::Context::full(&runtime).unwrap();
    context.with(|ctx| ctx.eval::<(), _>("throw 42;")).unwrap();
}

results in the following conversion error, with no way to retrieve the original error value:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: FromJs { from: "int", to: "object", message: None }', /home/rreverser/.cargo/git/checkouts/rquickjs-da202ee7abfef64e/29c5454/core/src/result.rs:478:41
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

For compatibility with arbitrary JS code, it should be possible to retrieve the original rquickjs::Value from the exception. As far as I can tell, QuickJS provides this functionality, and the conversion is imposed only at the rquickjs level.

holly-hacker commented 1 year ago

To be clear: this is a panic inside rquickjs and not in the user code.

RReverser commented 1 year ago

No, this is a panic in my own example code, where I'm unwrapping the result.

RReverser commented 1 year ago

Oh I see what you mean; yeah good point. I thought it's in my unwrap, but this makes it even worse.

DelSkayn commented 1 year ago

I have introduced a PR to fix this issue #148.

This will be a significant change to how javascript errors are handled in rquickjs but will allow you to retrieve any thrown javascript value.