dark_ruby
dark_ruby

Reputation: 7866

FromWasmAbi is not implemented for fn(SomeStruct) , while SomeStruct is #[wasm_bindgen]

I have a 3 structs and two types defined

type OnMoveEvent = fn(Board) -> ();
type OnGameOverEvent = fn(Player) -> ();

#[wasm_bindgen]
pub struct Game {
    on_move: OnMoveEvent,
    on_game_over: OnGameOverEvent,
    board: Board,
}
#[wasm_bindgen]
pub struct Board {/* ... */}
#[wasm_bindgen]
pub struct Player {/* ... */}

All 3 structs are wasm_bindgen and types can not be marked as wasm_bindgen. However types are just functions accepting structs and returning void

When I add wasm_bindgen to Game impl I get the following error

 --> src/game.rs:16:1
     |
  16 | #[wasm_bindgen]
     | ^^^^^^^^^^^^^^^ the trait `wasm_bindgen::convert::traits::FromWasmAbi` is not implemented for `fn(board::Board)`

That is because new has the following signature

pub fn new(on_move: OnMoveEvent, on_game_over: OnGameOverEvent) -> Game

It seemed to me that it should be simple to translate types as they are functions accepting wasm_bindgen structs, but it appears as it's not the case

Is this a bug or am I missing something?

The full code is here.

Upvotes: 4

Views: 2132

Answers (1)

dark_ruby
dark_ruby

Reputation: 7866

Going to answer my own question after a bit of research:

Because I was trying to pass some functions from JS to Rust, those can not be guaranteed to have certain signature.

Instead js-sys crate provides a way to Receiving JavaScript Closures in Exported Rust Functions

I changed my code to following:

#[wasm_bindgen]
pub struct Game {
  board: Board,
  on_cpu_move: js_sys::Function,
  on_game_over: js_sys::Function,
}

and new signature looks like this:

  pub fn new(on_move: js_sys::Function, on_game_over: js_sys::Function) -> Game {

Then I need to call a callback that a JS consumer is going to provide, this is done like so:

...
let state = self.board.state();
let this = JsValue::NULL;

if state.game_over {
   let _ = self.on_game_over.call0(&this);
} else {
   let board = JsValue::from(self.board);
   let _ = self.on_cpu_move.call1(&this, &board);
}
...

It is up to JS consumer to make sure they provide right types.

hope somebody finds it useful.

Upvotes: 3

Related Questions