Wasm-bindgen How do you create a function with an optional parameter object?

How do I create a function that allows the user to pass in an options object?
I'm exploring how to create a library that is idomatic to javascript.

// javascript
// How do I implement this...
wasm.greetWithOptions({
  message: 'Hello World Two',
  div: document.getElementById('name')
});

Working implementation:

// javascript
(async () => {
  const wasm = await import('./pkg/index').catch(console.error);
  wasm.greet('Hello World One', document.getElementById('name'));
})();

Rust: src/lib.rs:

use wasm_bindgen::prelude::*;
use web_sys::{HtmlDivElement};

// This works just fine
#[wasm_bindgen]
pub fn greet(message: &str, div: HtmlDivElement) {
  div.set_inner_text(message);
}

// What follows doesn't compile...
struct Options<'a> {
  message: &'a str,
  div: &'a HtmlDivElement,
}
#[wasm_bindgen(js_name = greetWithOptions)]
pub fn greet_with_options(options: &Options) {
  let div = options.div;
  let message = options.message;
  div.set_inner_text(message);
}

I have a gist example

Structs in wasm_bindgen are handled via serde, so they have to be serializable/deserializable. I also don't think that you can pass JavaScript objects (web-sys types) through that.

If you really want to do this, you have to take a JsValue and convert it to whatever you want yourself using the reflection API.

Also note that wasm_bindgen currently can't handle optional incoming parameters. If you compile in development mode, it adds a parameter count check that will fail. In release mode, it should work (since the type checks are not included then) and you should get JsValue::UNDEFINED.

Thank you so much! That worked great. It looks like they changed the behavior because if nothing is passed to rust, it no longer throws an error but you can check for undefined.

# [wasm_bindgen]
pub fn greet(ele: &JsValue, options: &JsValue) -> Result<(), JsValue> {
  match ele.dyn_ref::<HtmlDivElement>() {
    Some(div) => {
      if (options.is_undefined()) {
        div.set_inner_text("Hello from Rust");
      } else {
        let message: JsValue = Reflect::get(&options, &JsValue::from_str("message"))?;
        let message = message.as_string().unwrap();
        div.set_inner_text(&message);
      }
      Ok(())
    }
    None => Err(JsValue::from_str("ele must be a div"))
  }
}

Also, it's possible I'm not in development mode as I'm not sure how to set that or check it. I'm just using the example wasm_bindgen template in the book and using npm run serve

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.