### Serve files using miniserve Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html Alternative command to start a local HTTP server using `miniserve`. This is useful if Python is not installed or preferred. ```bash cargo install miniserve miniserve . --index "index.html" -p 8080 ``` -------------------------------- ### JavaScript Example Usage Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/arbitrary-data-with-serde.html Demonstrates how to call the Rust function `send_example_to_js` to get data and `receive_example_from_js` to send modified data back. Note how nested arrays are handled. ```javascript import { send_example_to_js, receive_example_from_js } from "example"; // Get the example object from wasm. let example = send_example_to_js(); // Add another "Vec" element to the end of the "Vec>" example.field2.push([5, 6]); // Send the example object back to wasm. receive_example_from_js(example); ``` -------------------------------- ### Resize the browser window using web-sys Source: https://rustwasm.github.io/docs/wasm-bindgen/web-sys/using-web-sys.html This example demonstrates how to get the browser window object and resize it to a specific dimension using the `resize_to` method. Ensure the 'Window' feature is enabled for web-sys. ```rust #![allow(unused_variables)] fn main() { use wasm_bindgen::prelude::*; use web_sys::Window; #[wasm_bindgen] pub fn make_the_window_small() { // Resize the window to 500px by 500px. let window = web_sys::window().unwrap(); window.resize_to(500, 500) .expect("could not resize the window"); } } ``` -------------------------------- ### Install wasm-bindgen CLI Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/cli.html Install the wasm-bindgen command-line interface using cargo. The -f flag forces reinstallation. ```bash cargo install -f wasm-bindgen-cli ``` -------------------------------- ### JavaScript Proxy Example Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/attributes/on-js-imports/indexing-getter-setter-deleter.html This JavaScript snippet demonstrates the usage of a Proxy object with custom get, set, and deleteProperty handlers. ```javascript const foo = new Proxy({}, { get(obj, prop) { return prop in obj ? obj[prop] : prop.length; }, set(obj, prop, value) { obj[prop] = value; }, deleteProperty(obj, prop) { delete obj[prop]; }, }); foo.ten; // 3 foo.ten = 10; foo.ten; // 10 delete foo.ten; foo.ten; // 3 ``` -------------------------------- ### Fetch API Example in Rust Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/fetch.html This Rust code demonstrates making an HTTP GET request to the GitHub API using the `fetch` API and processing the JSON response asynchronously. Ensure the `web-sys` crate is configured with the necessary features. ```rust use wasm_bindgen::prelude::*; use wasm_bindgen_futures::JsFuture; use web_sys::{Request, RequestInit, RequestMode, Response}; #[wasm_bindgen] pub async fn run(repo: String) -> Result { let opts = RequestInit::new(); opts.set_method("GET"); opts.set_mode(RequestMode::Cors); let url = format!("https://api.github.com/repos/{}/branches/master", repo); let request = Request::new_with_str_and_init(&url, &opts)?; request .headers() .set("Accept", "application/vnd.github.v3+json")?; let window = web_sys::window().unwrap(); let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?; // `resp_value` is a `Response` object. assert!(resp_value.is_instance_of::()); let resp: Response = resp_value.dyn_into().unwrap(); // Convert this other `Promise` into a rust `Future`. let json = JsFuture::from(resp.json()?).await?; // Send the JSON response back to JS. Ok(json) } ``` -------------------------------- ### Install wasm-bindgen-cli Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html Install the wasm-bindgen CLI tool, ensuring to use the same version as your wasm-bindgen dependency. ```bash cargo install wasm-bindgen-cli --vers "X.Y.Z" ``` -------------------------------- ### Appveyor Configuration for wasm-bindgen-test Source: https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/continuous-integration.html Set up Appveyor for Windows-based CI. This example installs Node.js, Rust nightly, and wasm-bindgen-cli, then runs tests in Chrome and Firefox. ```yaml install: - ps: Install-Product node 10 - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - rustc -V - cargo -V - rustup target add wasm32-unknown-unknown - cargo install wasm-bindgen-cli build: false test_script: # Test in Chrome. chromedriver is installed by default in appveyor. - set CHROMEDRIVER=C:\Tools\WebDriver\chromedriver.exe - cargo test --target wasm32-unknown-unknown - set CHROMEDRIVER= # Test in Firefox. geckodriver is also installed by default. - set GECKODRIVER=C:\Tools\WebDriver\geckodriver.exe - cargo test --target wasm32-unknown-unknown ``` -------------------------------- ### Install wasm-bindgen CLI Source: https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/usage.html Install the `wasm-bindgen-cli` tool using cargo to manage the test runner manually. Replace 'X.Y.Z' with your `wasm-bindgen` version. ```bash cargo install wasm-bindgen-cli --vers "X.Y.Z" ``` -------------------------------- ### Rust `char` type examples Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/types/char.html Demonstrates how to define functions that accept and return Rust `char` types using wasm-bindgen. ```rust #![allow(unused_variables)] fn main() { use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn take_char_by_value(x: char) {} #[wasm_bindgen] pub fn return_char() -> char { '🚀' } } ``` -------------------------------- ### web-sys src/lib.rs Example Source: https://rustwasm.github.io/docs/wasm-bindgen/contributing/web-sys/overview.html The main entry point for the web-sys crate, which includes generated bindings and sets up basic configurations like no_std and feature gating for API access. ```rust #![allow(unused_variables)] fn main() { //! Raw API bindings for Web APIs //! //! This is a procedurally generated crate from browser WebIDL which provides a //! binding to all APIs that browsers provide on the web. //! //! This crate by default contains very little when compiled as almost all of //! its exposed APIs are gated by Cargo features. The exhaustive list of //! features can be found in `crates/web-sys/Cargo.toml`, but the rule of thumb //! for `web-sys` is that each type has its own cargo feature (named after the //! type). Using an API requires enabling the features for all types used in the //! API, and APIs should mention in the documentation what features they //! require. #![doc(html_root_url = "https://docs.rs/web-sys/0.3")] #![no_std] #![allow(deprecated)] extern crate alloc; mod features; #[allow(unused_imports)] pub use features::*; pub use js_sys; pub use wasm_bindgen; /// Getter for the `Window` object /// /// [MDN Documentation] /// /// *This API requires the following crate features to be activated: `Window`* /// /// [MDN Documentation]: https://developer.mozilla.org/en-US/docs/Web/API/Window #[cfg(feature = "Window")] pub fn window() -> Option { use wasm_bindgen::JsCast; js_sys::global().dyn_into::().ok() } } ``` -------------------------------- ### Browser Performance Timing with Rust Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/performance.html Use `performance.now()` to get high-resolution timestamps in the browser. This example also shows how to convert performance timing values to `SystemTime` for human-readable output. ```rust #![allow(unused_variables)] fn main() { use std::time::{Duration, SystemTime, UNIX_EPOCH}; use wasm_bindgen::prelude::*; // lifted from the `console_log` example #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = console)] fn log(a: &str); } macro_rules! console_log { ($($t:tt)*) => (log(&format_args!($($t)*).to_string())) } #[wasm_bindgen(start)] fn run() { let window = web_sys::window().expect("should have a window in this context"); let performance = window .performance() .expect("performance should be available"); console_log!("the current time (in ms) is {}", performance.now()); let start = perf_to_system(performance.timing().request_start()); let end = perf_to_system(performance.timing().response_end()); console_log!("request started at {}", humantime::format_rfc3339(start)); console_log!("request ended at {}", humantime::format_rfc3339(end)); } fn perf_to_system(amt: f64) -> SystemTime { let secs = (amt as u64) / 1_000; let nanos = (((amt as u64) % 1_000) as u32) * 1_000_000; UNIX_EPOCH + Duration::new(secs, nanos) } } ``` -------------------------------- ### Use web-sys to resize the browser window Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html This example demonstrates how to use `web_sys::window()` and the `resize_to` method from the `Window` interface to resize the browser window. Ensure the `Window` feature is enabled in `Cargo.toml`. ```rust #![allow(unused_variables)] fn main() { use wasm_bindgen::prelude::*; use web_sys::Window; #[wasm_bindgen] pub fn make_the_window_small() { // Resize the window to 500px by 500px. let window = web_sys::window().unwrap(); window.resize_to(500, 500) .expect("could not resize the window"); } } ``` -------------------------------- ### Unsupported WebIDL Warning Example Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html Example of a warning log emitted by wasm_bindgen_webidl when it encounters an unsupported WebIDL interface during the build process. ```log WARN 2018-07-06T18:21:49Z: wasm_bindgen_webidl: Unsupported WebIDL interface: ... ``` -------------------------------- ### Cargo.toml for WebSocket Example Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/websockets.html Configure Cargo.toml to include necessary features for WebSocket objects and event handling in web_sys. This setup is required for connecting to echo servers and managing message events. ```toml [package] authors = ["The wasm-bindgen Developers"] edition = "2021" name = "websockets" publish = false version = "0.0.0" [lib] crate-type = ["cdylib"] [dependencies] js-sys = { path = "../../crates/js-sys" } wasm-bindgen = { path = "../../" } [dependencies.web-sys] features = [ "BinaryType", "Blob", "ErrorEvent", "FileReader", "MessageEvent", "ProgressEvent", "WebSocket", ] path = "../../crates/web-sys" [lints] workspace = true ``` -------------------------------- ### Post Message Example Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html This snippet demonstrates sending a message using `self.postMessage`. It's typically used in worker contexts. ```javascript self.postMessage({ type: "FETCH_WASM" }); ``` -------------------------------- ### Receive Example from JavaScript Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html Demonstrates how to receive a `JsValue` from JavaScript and deserialize it into a Rust struct using `serde_wasm_bindgen`. ```APIDOC ## Receive it from JavaScript with `serde_wasm_bindgen::from_value` Here's a function that will receive a `JsValue` parameter from JavaScript and then deserialize an `Example` from it: ```rust #[wasm_bindgen] pub fn receive_example_from_js(val: JsValue) { let example: Example = serde_wasm_bindgen::from_value(val).unwrap(); ... } ``` In the `JsValue` that JavaScript gets, `field1` will be a `Map`, `field2` will be a JavaScript `Array` whose members are `Array`s of numbers, and `field3` will be an `Array` of numbers. ``` -------------------------------- ### Rust Closure Example with `wasm-bindgen` Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/closures.html This example shows how to use closures in Rust with `wasm-bindgen` to interact with web APIs like `js_sys` and `web_sys`. It covers accessing stack data, setting up intervals, and handling click events. ```rust #![allow(unused_variables)] fn main() { use js_sys::{Array, Date}; use wasm_bindgen::prelude::*; use web_sys::{Document, Element, HtmlElement, Window}; #[wasm_bindgen(start)] fn run() -> Result<(), JsValue> { let window = web_sys::window().expect("should have a window in this context"); let document = window.document().expect("window should have a document"); // One of the first interesting things we can do with closures is simply // access stack data in Rust! let array = Array::new(); array.push(&"Hello".into()); array.push(&1.into()); let mut first_item = None; array.for_each(&mut |obj, idx, _arr| match idx { 0 => { assert_eq!(obj, "Hello"); first_item = obj.as_string(); } 1 => assert_eq!(obj, 1), _ => panic!("unknown index: {}", idx), }); assert_eq!(first_item, Some("Hello".to_string())); // Below are some more advanced usages of the `Closure` type for closures // that need to live beyond our function call. setup_clock(&window, &document)?; setup_clicker(&document); // And now that our demo is ready to go let's switch things up so // everything is displayed and our loading prompt is hidden. document .get_element_by_id("loading") .expect("should have #loading on the page") .dyn_ref::() .expect("#loading should be an `HtmlElement`") .style() .set_property("display", "none")?; document .get_element_by_id("script") .expect("should have #script on the page") .dyn_ref::() .expect("#script should be an `HtmlElement`") .style() .set_property("display", "block")?; Ok(()) } // Set up a clock on our page and update it each second to ensure it's got // an accurate date. // // Note the usage of `Closure` here because the closure is "long lived", // basically meaning it has to persist beyond the call to this one function. // Also of note here is the `.as_ref().unchecked_ref()` chain, which is how // you can extract `&Function`, what `web-sys` expects, from a `Closure` // which only hands you `&JsValue` via `AsRef`. fn setup_clock(window: &Window, document: &Document) -> Result<(), JsValue> { let current_time = document .get_element_by_id("current-time") .expect("should have #current-time on the page"); update_time(¤t_time); let a = Closure::::new(move || update_time(¤t_time)); window .set_interval_with_callback_and_timeout_and_arguments_0(a.as_ref().unchecked_ref(), 1000)?; fn update_time(current_time: &Element) { current_time.set_inner_html(&String::from( Date::new_0().to_locale_string("en-GB", &JsValue::undefined()), )); } // The instance of `Closure` that we created will invalidate its // corresponding JS callback whenever it is dropped, so if we were to // normally return from `setup_clock` then our registered closure will // raise an exception when invoked. // // Normally we'd store the handle to later get dropped at an appropriate // time but for now we want it to be a global handler so we use the // `forget` method to drop it without invalidating the closure. Note that // this is leaking memory in Rust, so this should be done judiciously! a.forget(); Ok(()) } // We also want to count the number of times that our green square has been // clicked. Our callback will update the `#num-clicks` div. // // This is pretty similar above, but showing how closures can also implement // `FnMut()`. fn setup_clicker(document: &Document) { let num_clicks = document .get_element_by_id("num-clicks") .expect("should have #num-clicks on the page"); let mut clicks = 0; let a = Closure::::new(move || { clicks += 1; num_clicks.set_inner_html(&clicks.to_string()); }); document .get_element_by_id("green-square") .expect("should have #green-square on the page") .dyn_ref::() .expect("#green-square be an `HtmlElement`") .set_onclick(Some(a.as_ref().unchecked_ref())); // See comments in `setup_clock` above for why we use `a.forget()`. a.forget(); } } ``` -------------------------------- ### HTML for Web Worker Setup Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/synchronous-instantiation.html The HTML file sets up a Web Worker and listens for messages. It handles fetching the WASM module bytes when requested by the worker and transfers them back. ```html Document ``` -------------------------------- ### JavaScript Module for Import Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/js-snippets.html This is an example of a JavaScript file that can be imported using `#[wasm_bindgen(module)]`. It must be written with ES module syntax. ```javascript export function add(a, b) { return a + b; } ``` -------------------------------- ### Unsupported WebIDL Construct Log Source: https://rustwasm.github.io/docs/wasm-bindgen/contributing/web-sys/logging.html This is an example of a warn-level log emitted by `wasm_bindgen_webidl` when it encounters WebIDL constructs it cannot translate. ```log WARN 2018-07-06T18:21:49Z: wasm_bindgen_webidl: Unsupported WebIDL interface: ... ``` -------------------------------- ### Send Example to JavaScript using Gloo Utils Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html Shows how to send a Rust struct to JavaScript by serializing it into a `JsValue` using `JsValueSerdeExt` from `gloo-utils`. ```APIDOC ## Sending and Receiving with `gloo_utils::format::JsValueSerdeExt` This approach uses JSON serialization for data transfer between Rust and JavaScript, offering an alternative to direct `serde_wasm_bindgen` manipulation. ```rust use gloo_utils::format::JsValueSerdeExt; use std::collections::HashMap; #[wasm_bindgen] pub fn send_example_to_js() -> JsValue { let mut field1 = HashMap::new(); field1.insert(0, String::from("ex")); let example = Example { field1, field2: vec![vec![1., 2.], vec![3., 4.]], field3: [1., 2., 3., 4.], }; JsValue::from_serde(&example).unwrap() } #[wasm_bindgen] pub fn receive_example_from_js(val: JsValue) { let example: Example = val.into_serde().unwrap(); ... } ``` ``` -------------------------------- ### Cargo.toml for 2D Canvas Example Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/2d-canvas.html Configure Cargo.toml to include necessary features for DOM manipulation and 2D canvas rendering. Ensure the correct paths for local crates are set. ```toml [package] authors = ["The wasm-bindgen Developers"] edition = "2021" name = "canvas" publish = false version = "0.0.0" [lib] crate-type = ["cdylib"] [dependencies] js-sys = { path = "../../crates/js-sys" } wasm-bindgen = { path = "../../" } [dependencies.web-sys] features = ['CanvasRenderingContext2d', 'Document', 'Element', 'HtmlCanvasElement', 'Window'] path = "../../crates/web-sys" [lints] workspace = true ``` -------------------------------- ### Basic js_namespace Usage Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/attributes/on-js-imports/js_namespace.html This example demonstrates how to use `js_namespace` to import functions and types from a specific JavaScript namespace like `console` or `Bar`. ```APIDOC ## Importing with `js_namespace` This attribute indicates that the JavaScript type is accessed through the given namespace. For example, the `WebAssembly.Module` APIs are all accessed through the `WebAssembly` namespace. `js_namespace` can be applied to any import (function or type) and whenever the generated JavaScript attempts to reference a name (like a class or function name) it'll be accessed through this namespace. ### Example: ```rust #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = console)] fn log(s: &str); type Foo; #[wasm_bindgen(constructor, js_namespace = Bar)] fn new() -> Foo; } log("hello, console!"); Foo::new(); ``` This is an example of how to bind namespaced items in Rust. The `log` and `Foo::new` functions will be available in the Rust module and will be invoked as `console.log` and `new Bar.Foo` in JavaScript. ``` -------------------------------- ### Run Headless Browser Tests with wasm-pack Source: https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/browsers.html Execute tests in multiple headless browsers by specifying flags for each browser. Ensure the respective browser and its WebDriver are installed on the system. ```bash wasm-pack test --headless --chrome --firefox --safari ``` -------------------------------- ### Rust Wasm-bindgen Paint Example Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/paint.html This Rust code sets up a canvas element, adds event listeners for mouse events, and implements a simple painting functionality using wasm-bindgen and web-sys. ```rust #![allow(unused_variables)] fn main() { use std::cell::Cell; use std::rc::Rc; use wasm_bindgen::prelude::*; #[wasm_bindgen(start)] fn start() -> Result<(), JsValue> { let document = web_sys::window().unwrap().document().unwrap(); let canvas = document .create_element("canvas")? .dyn_into::()?; document.body().unwrap().append_child(&canvas)?; canvas.set_width(640); canvas.set_height(480); canvas.style().set_property("border", "solid")?; let context = canvas .get_context("2d")? .unwrap() .dyn_into::()?; let context = Rc::new(context); let pressed = Rc::new(Cell::new(false)); { let context = context.clone(); let pressed = pressed.clone(); let closure = Closure::::new(move |event: web_sys::MouseEvent| { context.begin_path(); context.move_to(event.offset_x() as f64, event.offset_y() as f64); pressed.set(true); }); canvas.add_event_listener_with_callback("mousedown", closure.as_ref().unchecked_ref())?; closure.forget(); } { let context = context.clone(); let pressed = pressed.clone(); let closure = Closure::::new(move |event: web_sys::MouseEvent| { if pressed.get() { context.line_to(event.offset_x() as f64, event.offset_y() as f64); context.stroke(); context.begin_path(); context.move_to(event.offset_x() as f64, event.offset_y() as f64); } }); canvas.add_event_listener_with_callback("mousemove", closure.as_ref().unchecked_ref())?; closure.forget(); } { let closure = Closure::::new(move |event: web_sys::MouseEvent| { pressed.set(false); context.line_to(event.offset_x() as f64, event.offset_y() as f64); context.stroke(); }); canvas.add_event_listener_with_callback("mouseup", closure.as_ref().unchecked_ref())?; closure.forget(); } Ok(()) } } ``` -------------------------------- ### Build and Serve Wasm Project Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/without-a-bundler.html Commands to build the Wasm project for the web target and serve the files locally using Python's HTTP server or `miniserve`. ```bash wasm-pack build --target web python3 -m http.server 8080 ``` ```bash cargo install miniserve miniserve . --index "index.html" -p 8080 ``` -------------------------------- ### Using web-sys Crate Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html Explains how to add the `web-sys` crate as a dependency and enable specific Cargo features to access Web APIs. ```APIDOC ## Adding web-sys Dependency ### Cargo.toml Configuration ```toml [dependencies] wasm-bindgen = "0.2" [dependencies.web-sys] version = "0.3" features = [ # Enable features for specific Web APIs, e.g., "Window" ] ``` ```APIDOC ## Enabling Specific Features for web-sys ### Example: Accessing `window.resizeTo` To use `web_sys::Window::resize_to`, you need to enable the `Window` feature in `Cargo.toml`. ### Cargo.toml Configuration ```toml [dependencies.web-sys] version = "0.3" features = [ "Window" ] ``` ### Rust Code Example ```rust #![allow(unused_variables)] fn main() { use wasm_bindgen::prelude::*; use web_sys::Window; #[wasm_bindgen] pub fn make_the_window_small() { // Resize the window to 500px by 500px. let window = web_sys::window().unwrap(); window.resize_to(500, 500) .expect("could not resize the window"); } } ``` ``` ```APIDOC ## Cargo Features in `web-sys` ### Feature Requirements Each type in `web-sys` is gated by a Cargo feature. To access a type or method, you must enable the corresponding feature(s) in `Cargo.toml`. ### Example: `WebGlRenderingContext::compile_shader` This function requires features for its `self` type (`WebGlRenderingContext`) and its argument types (`WebGlShader`). ### Overloaded Functions `web-sys` provides multiple bindings for overloaded Web API functions to handle different argument types and overloads. ### Example: `Window::fetch` Overloads - `Window::fetch_with_str` - `Window::fetch_with_request` - `Window::fetch_with_str_and_init` - `Window::fetch_with_request_and_init` Note that different overloads may require different sets of Cargo features. ``` -------------------------------- ### Rust Library for Synchronous Initialization Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/synchronous-instantiation.html A simple Rust library exporting a `greet` function that logs a greeting to the console. This serves as the WebAssembly module to be synchronously initialized. ```rust #![allow(unused_variables)] fn main() { use wasm_bindgen::prelude::*; #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = console)] fn log(value: &str); } #[wasm_bindgen] pub fn greet(name: &str) { log(&format!("Hello, {}!", name)); } } ``` -------------------------------- ### JavaScript Variadic Function Example Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/attributes/on-js-imports/variadic.html This is an example of a JavaScript function that uses the rest parameter syntax to handle a variable number of arguments. ```javascript function sum(...rest) { let i; // the old way let old_way = 0; for (i=0; i`. Only one such function can be defined per module. ```rust #![allow(unused_variables)] fn main() { #[wasm_bindgen(start)] fn start() { // executed automatically ... } } ``` -------------------------------- ### Add wasm32-unknown-unknown Target Source: https://rustwasm.github.io/docs/wasm-bindgen/contributing/index.html Run this command after installing Rust to add the necessary target for WebAssembly compilation. ```rust rustup target add wasm32-unknown-unknown ``` -------------------------------- ### Rust Method with Return and Parameter Descriptions Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/attributes/on-rust-exports/description.html This example shows how to apply `#[wasm_bindgen(return_description)]` and `#[wasm_bindgen(param_description)]` to a method within an `impl` block for a struct. The `number` method of `FooList` demonstrates this, providing descriptions that will appear in the generated JavaScript. ```APIDOC ## Rust Method with Descriptions ### Description This Rust method `number` is part of the `FooList` struct. It takes an `index` and returns a `u32`. Descriptions for the parameter and return value are provided using `wasm-bindgen` attributes, which will be translated into JSDoc comments in the generated JavaScript class. ### Method Rust method definition ### Endpoint N/A (Rust method) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example ```rust #[wasm_bindgen] pub struct FooList { // properties } #[wasm_bindgen] impl FooList { /// Returns the number at the given index. #[wasm_bindgen(return_description = "the number at the given index")] pub fn number( &self, #[wasm_bindgen(param_description = "the index of the number to be returned")] index: u32, ) -> u32 { // function body } } ``` ### Response #### Success Response (N/A for Rust method) #### Response Example ```javascript export class FooList { /** * Returns the number at the given index. * * @param {number} index - the index of the number to be returned * @returns {number} the number at the given index */ number(index) { // ... } } ``` ``` -------------------------------- ### Calling Imported JavaScript Static Method Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html Example of calling the Rust function that represents a JavaScript static method. ```rust let instant = Date::now(); ``` -------------------------------- ### web-sys Crate Structure Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html This illustrates the directory layout of the web-sys crate, showing key files like build.rs, Cargo.toml, and src/lib.rs. ```text . ├── build.rs ├── Cargo.toml ├── README.md ├── src │ └── lib.rs └── webidls └── enabled └── ... ``` -------------------------------- ### Enabling Build Logs in web-sys Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html Command to build the web-sys crate with verbose output and enable logging for wasm_bindgen_webidl, useful for debugging WebIDL parsing issues. ```bash cd crates/web-sys RUST_LOG=wasm_bindgen_webidl cargo build -vv ``` -------------------------------- ### Run wasm-bindgen CLI Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/cli.html Execute the wasm-bindgen CLI tool with the path to your compiled WebAssembly binary. Options can be provided to customize the output. ```bash wasm-bindgen [options] ./target/wasm32-unknown-unknown/release/crate.wasm ``` -------------------------------- ### Nested js_namespace Usage Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/attributes/on-js-imports/js_namespace.html Specify nested JavaScript namespaces using an array of strings for `js_namespace`. This example binds to `window.document.write`. ```rust #![allow(unused_variables)] fn main() { #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = ["window", "document"])] fn write(s: &str); } write("hello, document!"); } ``` -------------------------------- ### Test web-sys Crate Source: https://rustwasm.github.io/docs/wasm-bindgen/contributing/web-sys/testing.html Run tests for the `web-sys` crate. Ensure you are in the correct directory and use the specified target and features. ```bash cd wasm-bindgen/crates/web-sys cargo test --target wasm32-unknown-unknown --all-features ``` -------------------------------- ### TypeScript Usage Example Source: https://rustwasm.github.io/docs/wasm-bindgen/reference/attributes/on-js-imports/typescript_type.html This snippet illustrates how to use the Rust-defined `TextStyle` and `ITextStyle` in TypeScript code, including instantiation and calling methods. ```APIDOC ## TypeScript Usage Example ### Description This example shows how to import and use the `TextStyle` and `ITextStyle` types, which are generated from Rust code using `wasm-bindgen`, within a TypeScript environment. It demonstrates creating instances of `TextStyle` and calling associated methods. ### Code Example ```typescript import { ITextStyle, TextStyle } from "./my_awesome_module"; const style: TextStyle = new TextStyle({ bold: true, italic: true, size: 42, }); const optional_style: TextStyle = TextStyle.optional_new(); ``` ``` -------------------------------- ### Rust WebRTC Data Channel Setup Source: https://rustwasm.github.io/docs/wasm-bindgen/examples/webrtc_datachannel.html Sets up two RtcPeerConnections and creates a data channel on the first. It configures message and data channel event handlers, and ICE candidate handling for both peers. ```rust #![allow(unused_variables)] fn main() { use js_sys::Reflect; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::JsFuture; use web_sys::{ MessageEvent, RtcDataChannelEvent, RtcPeerConnection, RtcPeerConnectionIceEvent, RtcSdpType, RtcSessionDescriptionInit, }; macro_rules! console_log { ($($t:tt)*) => (log(&format_args!($($t)*).to_string())) } macro_rules! console_warn { ($($t:tt)*) => (warn(&format_args!($($t)*).to_string())) } #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = console)] fn log(s: &str); #[wasm_bindgen(js_namespace = console)] fn warn(s: &str); } #[wasm_bindgen(start)] async fn start() -> Result<(), JsValue> { /* * Set up PeerConnections * pc1 <=> pc2 * */ let pc1 = RtcPeerConnection::new()?; console_log!("pc1 created: state {:?}", pc1.signaling_state()); let pc2 = RtcPeerConnection::new()?; console_log!("pc2 created: state {:?}", pc2.signaling_state()); /* * Create DataChannel on pc1 to negotiate * Message will be shown here after connection established * */ let dc1 = pc1.create_data_channel("my-data-channel"); console_log!("dc1 created: label {:?}", dc1.label()); let dc1_clone = dc1.clone(); let onmessage_callback = Closure::::new(move |ev: MessageEvent| { if let Some(message) = ev.data().as_string() { console_warn!("{:?}", message); dc1_clone.send_with_str("Pong from pc1.dc!").unwrap(); } }); dc1.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref())); onmessage_callback.forget(); /* * If negotiation has done, this closure will be called * */ let ondatachannel_callback = Closure::::new(move |ev: RtcDataChannelEvent| { let dc2 = ev.channel(); console_log!("pc2.ondatachannel!: {:?}", dc2.label()); let onmessage_callback = Closure::::new(move |ev: MessageEvent| { if let Some(message) = ev.data().as_string() { console_warn!("{:?}", message); } }); dc2.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref())); onmessage_callback.forget(); let dc2_clone = dc2.clone(); let onopen_callback = Closure::::new(move || { dc2_clone.send_with_str("Ping from pc2.dc!").unwrap(); }); dc2.set_onopen(Some(onopen_callback.as_ref().unchecked_ref())); onopen_callback.forget(); }); pc2.set_ondatachannel(Some(ondatachannel_callback.as_ref().unchecked_ref())); ondatachannel_callback.forget(); /* * Handle ICE candidate each other * */ let pc2_clone = pc2.clone(); let onicecandidate_callback1 = Closure::::new(move |ev: RtcPeerConnectionIceEvent| { if let Some(candidate) = ev.candidate() { console_log!("pc1.onicecandidate: {:#?}", candidate.candidate()); let _ = pc2_clone.add_ice_candidate_with_opt_rtc_ice_candidate(Some(&candidate)); } }); pc1.set_onicecandidate(Some(onicecandidate_callback1.as_ref().unchecked_ref())); onicecandidate_callback1.forget(); let pc1_clone = pc1.clone(); let onicecandidate_callback2 = Closure::::new(move |ev: RtcPeerConnectionIceEvent| { if let Some(candidate) = ev.candidate() { console_log!("pc2.onicecandidate: {:#?}", candidate.candidate()); let _ = pc1_clone.add_ice_candidate_with_opt_rtc_ice_candidate(Some(&candidate)); } }); pc2.set_onicecandidate(Some(onicecandidate_callback2.as_ref().unchecked_ref())); onicecandidate_callback2.forget(); /* * Send OFFER from pc1 to pc2 * */ let offer = JsFuture::from(pc1.create_offer()).await?; let offer_sdp = Reflect::get(&offer, &JsValue::from_str("sdp"))? .as_string() .unwrap(); console_log!("pc1: offer {:?}", offer_sdp); let offer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Offer); offer_obj.set_sdp(&offer_sdp); let sld_promise = pc1.set_local_description(&offer_obj); JsFuture::from(sld_promise).await?; console_log!("pc1: state {:?}", pc1.signaling_state()); /* * Receive OFFER from pc1 * Create and send ANSWER from pc2 to pc1 * */ let offer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Offer); offer_obj.set_sdp(&offer_sdp); let srd_promise = pc2.set_remote_description(&offer_obj); JsFuture::from(srd_promise).await?; console_log!("pc2: state {:?}", pc2.signaling_state()); let answer = JsFuture::from(pc2.create_answer()).await?; let answer_sdp = Reflect::get(&answer, &JsValue::from_str("sdp"))? .as_string() .unwrap(); console_log!("pc2: answer {:?}", answer_sdp); // The rest of the code would typically involve setting the remote description on pc1 // and potentially sending the answer SDP back. Ok(()) } } ``` -------------------------------- ### Exporting a Rust function to JS Source: https://rustwasm.github.io/docs/wasm-bindgen/print.html Annotate Rust functions with `#[wasm_bindgen]` to export them for use in JavaScript. This example shows a simple greet function. ```rust #![allow(unused_variables)] fn main() { pub fn greet(name: &str) -> String { // ... } } ``` ```rust #![allow(unused_variables)] fn main() { #[wasm_bindgen] pub fn greet(name: &str) -> String { // ... } } ```