Skip to main content

wasm_bindgen_derive/
lib.rs

1/*!
2This is a specialized crate exporting a derive macro [`TryFromJsValue`]
3that serves as a basis for workarounds for some lapses of functionality in
4[`wasm-bindgen`](https://crates.io/crates/wasm-bindgen).
5
6
7## Optional arguments and return values
8
9`wasm-bindgen` supports method arguments of the form `Option<T>`,
10where `T` is an exported type, but it has an unexpected side effect on the JS side:
11the value passed to a method this way gets consumed (mimicking Rust semantics).
12See [wasm-bindgen#2370](https://github.com/rustwasm/wasm-bindgen/issues/2370).
13`Option<&T>` is not currently supported, but an equivalent behavior can be implemented manually.
14
15```
16use js_sys::Error;
17use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
18use wasm_bindgen_derive::{TryFromJsValue, try_from_js_option, into_js_option};
19
20// Derive `TryFromJsValue` for the target structure (note that it has to come
21// before the `[#wasm_bindgen]` attribute, and requires `Clone`):
22#[derive(TryFromJsValue)]
23#[wasm_bindgen]
24#[derive(Clone)]
25struct MyType(usize);
26
27// To have a correct typing annotation generated for TypeScript, declare a custom type.
28#[wasm_bindgen]
29extern "C" {
30    #[wasm_bindgen(typescript_type = "MyType | undefined")]
31    pub type OptionMyType;
32}
33
34// Use this type in the function signature.
35#[wasm_bindgen]
36pub fn option_example(value: &OptionMyType) -> Result<OptionMyType, Error> {
37    // Use a helper to extract the typed value
38    let typed_value = try_from_js_option::<MyType>(value).map_err(|err| Error::new(&err))?;
39
40    // Now we have `typed_value: Option<MyType>`.
41
42    // Return it
43    // Note that if `typed_value` is `None`, `into_js_option()` creates a `JsValue::UNDEFINED`.
44    Ok(into_js_option(typed_value))
45}
46```
47
48## Vector arguments
49
50With the closing of [wasm-bindgen#111](https://github.com/rustwasm/wasm-bindgen/issues/111),
51it is now possible to return `Vec<MyType>` values.
52Having an argument of type `Vec<MyType>` compiles, but results in an unexpected behavior
53similar to that with `Option<MyType>`: all the elements of the input array
54(but not the array itself) are invalidated on the JS side.
55So this crate can still be used to take array arguments without invalidating them.
56
57```
58use js_sys::Error;
59use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
60use wasm_bindgen_derive::{TryFromJsValue, try_from_js_array, into_js_array};
61
62#[derive(TryFromJsValue)]
63#[wasm_bindgen]
64#[derive(Clone)]
65struct MyType(usize);
66
67// To have a correct typing annotation generated for TypeScript, declare a custom type.
68#[wasm_bindgen]
69extern "C" {
70    #[wasm_bindgen(typescript_type = "MyType[]")]
71    pub type MyTypeArray;
72}
73
74// Use this type in the function signature.
75#[wasm_bindgen]
76pub fn vec_example(val: &MyTypeArray) -> Result<MyTypeArray, Error> {
77    // Use a helper to extract the typed array
78    let typed_array = try_from_js_array::<MyType>(val).map_err(|err| Error::new(&err))?;
79
80    // Now we have `typed_array: Vec<MyType>`.
81
82    // Return the array
83    Ok(into_js_array(typed_array))
84}
85
86// Post wasm-bindgen 0.2.91, we can just return a vector
87#[wasm_bindgen]
88pub fn vec_example_simplified(val: &MyTypeArray) -> Result<Vec<MyType>, Error> {
89    // Use a helper to extract the typed array
90    let typed_array = try_from_js_array::<MyType>(val).map_err(|err| Error::new(&err))?;
91
92    // Now we have `typed_array: Vec<MyType>`.
93
94    // Return the array
95    Ok(typed_array)
96}
97```
98*/
99#![doc(html_root_url = "https://docs.rs/wasm-bindgen-derive")]
100#![no_std]
101
102// Needed for the generated code to work.
103/// Re-exported standard library `alloc` to use in the generated code.
104pub extern crate alloc;
105
106mod helpers;
107
108pub use helpers::{into_js_array, into_js_option, try_from_js_array, try_from_js_option};
109pub use wasm_bindgen_derive_macro::TryFromJsValue;