Types in wasm-bindgen - The wasm-bindgen Guide (original) (raw)

  1. Introduction
  2. 1. Examples
    1. 1.1. Hello, World!
    2. 1.2. Using console.log
    3. 1.3. Small Wasm files
    4. 1.4. Without a Bundler
    5. 1.5. Synchronous Instantiation
    6. 1.6. Importing functions from JS
    7. 1.7. Working with char
    8. 1.8. js-sys: WebAssembly in WebAssembly
    9. 1.9. web-sys: DOM hello world
    10. 1.10. web-sys: Closures
    11. 1.11. web-sys: performance.now
    12. 1.12. web-sys: using fetch
    13. 1.13. web-sys: Weather report
    14. 1.14. web-sys: canvas hello world
    15. 1.15. web-sys: canvas Julia set
    16. 1.16. web-sys: WebAudio
    17. 1.17. web-sys: WebGL
    18. 1.18. web-sys: WebSockets
    19. 1.19. web-sys: WebRTC DataChannel
    20. 1.20. web-sys: requestAnimationFrame
    21. 1.21. web-sys: A Simple Paint Program
    22. 1.22. web-sys: Wasm in Web Worker
    23. 1.23. Parallel Raytracing
    24. 1.24. Wasm Audio Worklet
    25. 1.25. web-sys: A TODO MVC App
  3. 2. Reference
    1. 2.1. Deployment
    2. 2.2. JS snippets
    3. 2.3. Static JS Objects
    4. 2.4. Passing Rust Closures to JS
    5. 2.5. Receiving JS Closures in Rust
    6. 2.6. Promises and Futures
    7. 2.7. Iterating over JS Values
    8. 2.8. Arbitrary Data with Serde
    9. 2.9. Accessing Properties of Untyped JS Values
    10. 2.10. Working with Duck-Typed Interfaces
    11. 2.11. Command Line Interface
    12. 2.12. Optimizing for Size
    13. 2.13. Supported Rust Targets
    14. 2.14. Supported Browsers
    15. 2.15. Support for Weak References
    16. 2.16. Support for Reference Types
    17. 2.17. Supported Types
      1. 2.17.1. Imported JavaScript Types
      2. 2.17.2. Exported Rust Types
      3. 2.17.3. JsValue
      4. 2.17.4. Box<[T]> and Vec
      5. 2.17.5. *const T and *mut T
      6. 2.17.6. NonNull
      7. 2.17.7. Numbers
      8. 2.17.8. bool
      9. 2.17.9. char
      10. 2.17.10. str
      11. 2.17.11. String
      12. 2.17.12. Number Slices
      13. 2.17.13. Boxed Number Slices
      14. 2.17.14. Result<T, E>
    18. 2.18. #[wasm_bindgen] Attributes
      1. 2.18.1. On JavaScript Imports
        1. 2.18.1.1. catch
          1. 2.18.1.2. constructor
          2. 2.18.1.3. extends
          3. 2.18.1.4. getter and setter
          4. 2.18.1.5. final
          5. 2.18.1.6. indexing_getter, indexing_setter, and indexing_deleter
          6. 2.18.1.7. js_class = "Blah"
          7. 2.18.1.8. js_name
          8. 2.18.1.9. js_namespace
          9. 2.18.1.10. method
          10. 2.18.1.11. module = "blah"
          11. 2.18.1.12. raw_module = "blah"
          12. 2.18.1.13. no_deref
          13. 2.18.1.14. static_method_of = Blah
          14. 2.18.1.15. structural
          15. 2.18.1.16. typescript_type
          16. 2.18.1.17. variadic
          17. 2.18.1.18. vendor_prefix
      2. 2.18.2. On Rust Exports
        1. 2.18.2.1. constructor
          1. 2.18.2.2. js_name = Blah
          2. 2.18.2.3. js_class = Blah
          3. 2.18.2.4. readonly
          4. 2.18.2.5. skip
          5. 2.18.2.6. skip_jsdoc
          6. 2.18.2.7. start
          7. 2.18.2.8. main
          8. 2.18.2.9. typescript_custom_section
          9. 2.18.2.10. getter and setter
          10. 2.18.2.11. inspectable
          11. 2.18.2.12. skip_typescript
          12. 2.18.2.13. getter_with_clone
          13. 2.18.2.14. unchecked_return_type and unchecked_param_type
          14. 2.18.2.15. return_description and param_description
  4. 3. web-sys
    1. 3.1. Using web-sys
    2. 3.2. Cargo Features
    3. 3.3. Function Overloads
    4. 3.4. Type Translations
    5. 3.5. Inheritance
    6. 3.6. Unstable APIs
  5. 4. Testing with wasm-bindgen-test
    1. 4.1. Usage
    2. 4.2. Writing Asynchronous Tests
    3. 4.3. Testing in Headless Browsers
    4. 4.4. Continuous Integration
    5. 4.5. Coverage (Experimental)
  6. 5. Contributing to wasm-bindgen
    1. 5.1. Testing
  7. 5.2. Internal Design
    1. 5.2.1. JS Objects in Rust
      1. 5.2.2. Exporting a function to JS
      2. 5.2.3. Exporting a struct to JS
      3. 5.2.4. Importing a function from JS
      4. 5.2.5. Importing a class from JS
      5. 5.2.6. Rust Type conversions
      6. 5.2.7. Types in wasm-bindgen
  8. 5.3. js-sys
    1. 5.3.1. Testing
      1. 5.3.2. Adding More APIs
  9. 5.4. web-sys
    1. 5.4.1. Overview
      1. 5.4.2. Testing
      2. 5.4.3. Logging
      3. 5.4.4. Supporting More Web APIs
  10. 5.5. Publishing
  11. 5.6. Team

The `wasm-bindgen` Guide

Communicating types to wasm-bindgen

The last aspect to talk about when converting Rust/JS types amongst one another is how this information is actually communicated. The #[wasm_bindgen] macro is running over the syntactical (unresolved) structure of the Rust code and is then responsible for generating information that wasm-bindgen the CLI tool later reads.

To accomplish this a slightly unconventional approach is taken. Static information about the structure of the Rust code is serialized via JSON (currently) to a custom section of the Wasm executable. Other information, like what the types actually are, unfortunately isn't known until later in the compiler due to things like associated type projections and typedefs. It also turns out that we want to convey "rich" types like FnMut(String, Foo, &JsValue) to the wasm-bindgen CLI, and handling all this is pretty tricky!

To solve this issue the #[wasm_bindgen] macro generates executable functions which "describe the type signature of an import or export". These executable functions are what the WasmDescribe trait is all about:


# #![allow(unused_variables)]
#fn main() {
pub trait WasmDescribe {
    fn describe();
}
#}

While deceptively simple this trait is actually quite important. When you write, an export like this:


# #![allow(unused_variables)]
#fn main() {
#[wasm_bindgen]
fn greet(a: &str) {
    // ...
}
#}

In addition to the shims we talked about above which JS generates the macro_also_ generates something like:

#[no_mangle]
pub extern "C" fn __wbindgen_describe_greet() {
    <dyn Fn(&str)>::describe();
}

Or in other words it generates invocations of describe functions. In doing so the __wbindgen_describe_greet shim is a programmatic description of the type layouts of an import/export. These are then executed when wasm-bindgen runs! These executions rely on an import called __wbindgen_describe which passes oneu32 to the host, and when called multiple times gives a Vec<u32>effectively. This Vec<u32> can then be reparsed into an enum Descriptorwhich fully describes a type.

All in all this is a bit roundabout but shouldn't have any impact on the generated code or runtime at all. All these descriptor functions are pruned from the emitted Wasm file.