Skip to content

Split crate into "standalone" and "JS" components #1841

Open
@alexcrichton

Description

@alexcrichton

Over time wasm-bindgen has picked up more features to follow the WebAssembly proposals, namely the interface types proposal. Additionally wasm-bindgen has been used for new embeddings such as WASI! One of the major goals of interface types is to also help bring wasm code to many more places outside of the web browser.

Currently for this "outside the web browser" use case wasm-bindgen is acting as Rust's implementation of interface types (to follow the standard), and I think that's likely to continue being the case into the future. Unfortunately though this causes a bit of an impedance mismatch!

  • From the start wasm-bindgen was built for the web and assumes JS. Lots of functionality isn't available in standalone webassembly (almost none of the APIs on JsValue, classes, etc)
  • Currently debug builds, by default, fail for the interface types target because they don't optimize out calls to __wbindgen_throw. There are no intrinsics with a standalone wasm file!
  • Restrictions on the web are not actually restrictions everywhere else. We support u64/i64 on the web by passing two i32 components, but Support for i64/u64 in interface types #1837 points out this is natively supported by all other runtimes.

Overall I think that to continue to faithfully pursue the standalone outside-the-web browser use case we'll want to do something about the current organization. I don't think this should be isolated to just the wasm32-wasi target, but it should include it!

I would expect an organization where you still use #[wasm_bindgen]-the-macro but if you're in a standalone environment you'd have a type like Anyref instead of JsValue. Additionally you would have no access to intrinsics in a standalone environment, unlike the JS environment. I think we'll want to tweak the features available in #[wasm_bindgen] as well, where if you're in a standalone environment we require a module for all imports and don't support any features like js_namespace and such.

I sort of envision this happening by doing something like the following:

  • Spilt out a wasm-bindgen-core crate. This crate defines the Anyref type, uses zero intrinsics, and defines all the basic conversion traits.
  • Add a dependency from wasm-bindgen-core to wasm-bindgen-macro, and reexport it
  • The current wasm-bindgen crate would then depend on wasm-bindgen-core, reexporting most of its functionality and layering JsValue on top of Anyref.
  • Update wasm-bindgen-macro with an off-by-default js feature (or something like that). When enabled this enables all the support for things like js_namespace and such. The wasm-bindgen-core crate would not turn this feature on, but wasm-bindgen would
  • If necessary add a js feature to wasm-bindgen-core which wasm-bindgen would activate, which would tweak impls like the ABI of i64/u64.

The general user experience would then be that if you're using wasm-bindgen today, nothing changes. For standalone use-cases though that do not intend on targeting the web specifically, you'd use the wasm-bindgen-core crate. The wasm-bindgen-core crate would statically ensure that you stay within what interface types are supported. This means no support for fancy types like closures (until they're added to the standard eventually). The hope here is that you can get errors in crate compilation long before you actually run the wasm-bindgen CLI tool.

In any case I'm curious what others think of this strategy? Is wasm-bindgen still an appropriate place for all this? Do others think that this should all be split out somehow? Should we send a PR tomorrow? (etc, etc)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions