Skip to content

Interaction between Rust wasm/foreign modules and encapsulation #92

@dflemstr

Description

@dflemstr

I hope this is the right place for this discussion; I tried finding a forum that would reach the right target audience and this seemed like the best place.

I've been working with Rust/wasm for quite a while. For that I've been using wasm-bindgen quite heavily (for a not-yet-released project) using a Webpack loader I've authored: https://github.com/dflemstr/rust-native-wasm-loader

One thing I have noticed is that there doesn't seem to be a clear direction regarding how code modules are to be treated between Rust and foreign modules (such as ES6 modules or other wasm modules) on the source level.

Incidentally, it seems to be working similar to C but not consistently. This behavior is quite confusing when interfacing between two languages that both support modules/namespacing (Rust+JS)

Remember, this is the perhaps naive impression of somebody using Rust together with wasm. I'm aware of how the current wasm FFI is closely modeled after the C FFI.

Imagine the following tree (with the module hierarchy like you would expect):

.
└── src
    ├── lib.rs
    ├── reducer
    │   └── editor.js
    └── util
        ├── leftpad.js
        └── leftpad.rs

What should the semantics be around visibility and scope for these files? This is what my intuition would tell me:

  • editor.js should import leftpad.rs as ../util/leftpad.rs, or import some myrustlib.wasm module where the symbol is available as util::leftpad::xyz in some fashion.
  • leftpad.rs should import editor.js as ../reducer/editor.js.
  • (Stretch:) There should be a separate notion of "exported in my Rust crate" and "available to Javascript"
  • (Stretch:) It should be possible to mark a symbol as being available only in the util module, so that editor.js would not see such a symbol defined in leftpad.rs, but leftpad.js would be able to.

With that said, here is what current tools are doing:

  • Raw rustc symbols that are export "C"'d are exported in a global shared namespace.
  • wasm-bindgen will export everything marked with #[wasm_bindgen] also in a global shared namespace (including more advanced things such as structs/classes etc).
  • wasm-bindgen will resolve all imports (#[wasm_bindgen(module = "...")]) relative to the location of the final generated module artifact, wherever that may be.
  • wasm-bindgen only supports symbols that are both crate-public and exported.
  • All imports/exports have no notion of encapsulation.
  • (Feel free to suggest other items if we want to make a complete list; I just highlighted some examples)

I find this behavior surprising and feel like one could do either of these things:

  • Prohibit imports/exports except on the crate top level (lib.rs/main.rs) and resolve them relative to that location.
  • Properly namespace imports/exports such that they behave as I described above, or in some other intuitive fashion.

Does this sound reasonable? What are everybody's thoughts on this?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions