diff --git a/src/SUMMARY.md b/src/SUMMARY.md index cdc8cf88..d531ba2d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -298,11 +298,13 @@ - [WebAssembly basics](webassembly.md) - [Load a WASM module](webassembly/load-wasm-module.md) -- [Import Method](webassembly/import-method.md) - - [web-sys](webassembly/web-sys.md) - [Expose a method](webassembly/expose-method.md) -- [Error handling](webassembly/error-handling.md) + - [Error handling for exposed methods](webassembly/expose-method/error-handling.md) +- [Import Method](webassembly/import-method.md) + - [Error handling for imported methods](webassembly/import-method/error-handling.md) + - [web-sys](webassembly/import-method/web-sys.md) - [Expose user-defined Rust types](webassembly/expose-rust-type.md) +- [Import user-defined Javascript types](webassembly/import-js-type.md) - [Borrow Checker](webassembly/borrow-checker.md) # Final Words diff --git a/src/webassembly/error-handling.md b/src/webassembly/expose-method/error-handling.md similarity index 87% rename from src/webassembly/error-handling.md rename to src/webassembly/expose-method/error-handling.md index 37a6a47b..7014ff5c 100644 --- a/src/webassembly/error-handling.md +++ b/src/webassembly/expose-method/error-handling.md @@ -5,7 +5,7 @@ will automatically throw an error if the variant of the return value is `Result: ```rust #[wasm_bindgen] -pub fn str_to_int(s: &str) -> Option { +pub fn str_to_int(s: &str) -> Result { s.parse::() .map_err(|_| JsValue::from_str("Failed to parse string")) } @@ -21,7 +21,7 @@ pub fn str_to_int(s: &str) -> Option { ``` -Javascript (click on the wasm output box) to parse the string: +Javascript, click on the wasm output box to parse the string: ```javascript import init, {set_panic_hook, str_to_int} from '/wasm/project.js'; @@ -49,6 +49,6 @@ import init, {set_panic_hook, str_to_int} from '/wasm/project.js';
* Click on the wasm output box to see the output -* `?` and other error handling toos also work +* `?` and other error handling tools are also supported
\ No newline at end of file diff --git a/src/webassembly/import-js-type.md b/src/webassembly/import-js-type.md new file mode 100644 index 00000000..9187259d --- /dev/null +++ b/src/webassembly/import-js-type.md @@ -0,0 +1,89 @@ +# Import user-defined Javascript types + +User-defined Javascript types can be imported by declaring the relevant methods as `extern "C"` just like +other foreign functions. + +For instance, let's declare a class `OutputBox` + +```javascript +import init, {set_panic_hook, edit_box} from '/wasm/project.js'; + +class OutputBox { + constructor(element) { + this.element = element; + this.lastText = null; + } + + setText(text) { + this.element.innerHTML = text; + } + + get currentText() { + return this.element.innerHTML; + } +} + +window.OutputBox = OutputBox; + +(async () => { + // Run the init method to initiate the WebAssembly module. + await init(); + set_panic_hook(); + const wasmoutput = document.querySelector('#wasmoutput'); + const outputBox = new OutputBox(wasmoutput); + const input = document.createElement('input'); + document.body.appendChild(input); + wasmoutput.onclick = () => { + const inputValue = input.value; + edit_box(outputBox, inputValue); + }; +})(); +``` + +It can be imported as such in Rust + +```rust +#[wasm_bindgen] +extern "C" { + pub type OutputBox; + + #[wasm_bindgen(constructor)] + pub fn new(text: i32) -> OutputBox; + + #[wasm_bindgen(method)] + pub fn setText(this: &OutputBox, text: &str); + + // Has to return owned + #[wasm_bindgen(method, getter)] + pub fn lastText(this: &OutputBox) -> Option; + + #[wasm_bindgen(method, setter)] + pub fn set_lastText(this: &OutputBox, text: Option); + + #[wasm_bindgen(method, getter)] + pub fn currentText(this: &OutputBox) -> String; +} + +#[wasm_bindgen] +pub fn edit_box(output_box: &OutputBox, text: &str) { + match text { + "reset" => output_box.set_lastText(None), + "recover" => { + if let Some(last_text) = output_box.lastText() { + output_box.setText(&last_text); + } else { + output_box.setText("No last text"); + } + } + "save" => output_box.set_lastText(Some(output_box.currentText())), + _ => output_box.setText(text), + } +} +``` + +
+ +* Getters and Setters have to be declared with an added parameter in the proc macro. +* `null` and `undefined` can be both represented by `Option::None` + +
\ No newline at end of file diff --git a/src/webassembly/import-method/error-handling.md b/src/webassembly/import-method/error-handling.md new file mode 100644 index 00000000..8cc9d0a9 --- /dev/null +++ b/src/webassembly/import-method/error-handling.md @@ -0,0 +1,18 @@ +# Error handling for imported Javascript methods + +Javascript methods that throw can be imported in Rust like this: + +```javascript +window.throwsIfPair = (num) => { + if (num % 2 === 0) throw new Error("Pair number"); + return num; +}; +``` + +```rust +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(catch)] + pub fn throwsIfPair(text: i32) -> Result; +} +``` diff --git a/src/webassembly/web-sys.md b/src/webassembly/import-method/web-sys.md similarity index 100% rename from src/webassembly/web-sys.md rename to src/webassembly/import-method/web-sys.md