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

Breaking JS changes: Driver.new(InitOptions); WasmResult wrapper/.unwrap(); parseStyleMetadata #94

Merged
merged 22 commits into from
Dec 3, 2020

Conversation

cormacrelf
Copy link
Collaborator

@cormacrelf cormacrelf commented Dec 3, 2020

The diff on the wasm README should give you a good idea of what's changed here. I've bundled up all the breakages in one go, hopefully that is more convenient than one new breakage every day.

  • Driver.new now takes a single argument, typed as InitOptions, to accomodate optional configurations and flags.
  • New API: parseStyleMetadata. Useful for parsing dependent styles especially, but works for all.
  • renamed await driver.fetchAll() to await driver.fetchLocales(), documented better
  • Nearly every Driver API now wraps its return value in a WasmResult, to avoid potential stack problems with wasm-bindgen's leaky implementation of automatic error-throwing. You can get errors thrown again with .unwrap() after each call, which is a good default because otherwise these errors will just sit there unnoticed. It's not the greatest, but it avoids a memory leak and stack overflow.
  • Those JS wrappers throw two kinds of error which both inherit from CiteprocRsError: CslStyleError and CiteprocRsDriverError. Both are globals (or in the case of Zotero, added to Zotero.CiteprocRs.*)
  • The fact of custom JS being shipped with the module means the more hacky builds need an additonal file included. It's called citeproc_rs_wasm_include.js.
  • There's a new _zotero build that needs no custom build script replace("export class", "class") hacks. It places exports on Zotero.CiteprocRs as well as module.exports.

…s stack overflows

This way we never call wasm_bindgen's throw_val, which doesn't clean up after itself.

Before:

    driver.batchedUpdates()

After:

    driver.batchedUpdates().unwrap() // may throw an error

The object with the unwrap() method is shaped like { Ok: T } or { Err: Error }.
This object is included in `crates/wasm/src/include.js`, which most builds can
import/bundle by themselves, but not no-modules, which doesn't work yet.
Not sure if this is right, but ok
I remembered it was necessary in the browser/esm/node code as well.
At least now the TypeScript defines them as globals, so that mistake
is more obvious.
Wasn't actually necessary to solve
#78
But nevertheless.
So this build script is getting a bit involved, but that's
the fragmented JS module ecosystem for you.
@cormacrelf cormacrelf merged commit 57a51ba into master Dec 3, 2020
@cormacrelf cormacrelf deleted the unwrap branch December 3, 2020 16:39
@adomasven
Copy link
Member

  • Nearly every Driver API now wraps its return value in a WasmResult, to avoid potential stack problems with wasm-bindgen's leaky implementation of automatic error-throwing. You can get errors thrown again with .unwrap() after each call, which is a good default because otherwise these errors will just sit there unnoticed. It's not the greatest, but it avoids a memory leak and stack overflow.

This is unnecessarily clunky on the client side of the Driver. Can't it just return the value or throw whatever error it was going to throw, i.e. call unwrap() automatically for the client? I can't think of any benefit of being able to unwrap things manually and possibly handle that with unwrap_err().

@cormacrelf
Copy link
Collaborator Author

Right, it can throw errors automatically by using wasm-bindgen’s generated code for this but not without leaking stack space in the code that I don’t control. I didn’t do it just to give you this not very javascripty API. There are no benefits apart from not having a memory leak.

As for “just throw them (manually)”, I can’t because throwing an error uses the same leaky method as the glue code. Simply: if you throw a JS error inside the WebAssembly code, it never bubbles back up through the WebAssembly, because it is not a JS VM stack! The JS VM cannot unwind it. So it never resets the stack pointer. AFAIK this kind of thing may be the only way to solve rustwasm/wasm-bindgen#1963 at all. Once we have ESR 78 running and a couple of WebAssembly spec items are no longer missing, and so we’re no longer pinned to an old wasm-bindgen, then maybe all this goes away if I can upstream the solution in some way that makes it throw them automatically again but from outside the WASM stack. That seems pretty viable to me, I’ll report on this upstream.

I can write a complete wrapper ie “unwrapper” class that does this for you if you really want but it is only about ten unwraps, vs a long wrapper class that would have to be kept in sync.

@adomasven
Copy link
Member

It isn't strictly necessary given that this is primarily a Rust implementation of citeproc, but if there's WASM JS bindings they may as well take the extra step and do this sort of thing. If we're going out of the way to make the API more convenient for current and future clients in other issues, making it clunky like this here is a step back. This isn't top priority, since I imagine it is not that easy to do given all the different environments that you're generating for means that adding a wrapper would be quite a bit of work, but something certainly worth considering.

@cormacrelf
Copy link
Collaborator Author

In the interests of not breaking again for reasons people don't care about, yeah.

@cormacrelf cormacrelf added A-wasm Area: wasm package on npm breaking Breaking change A-crates/csl Area: csl crate A-crates/citeproc Area: citeproc crate labels Sep 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-crates/citeproc Area: citeproc crate A-crates/csl Area: csl crate A-wasm Area: wasm package on npm breaking Breaking change
Development

Successfully merging this pull request may close these issues.

None yet

2 participants