3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue.jsでwasm-bindgen(Rust+WebAssembry)の入出力を扱う

3
Last updated at Posted at 2020-08-10

wasm-bindgenでHello,Worldできたという記事は多いが、wasmを本格的に扱うならVue.jsでJSONをやりとりするところまでテンプレにしておきたい。wasmのモジュールを読み込む前にvar app = new Vue()をやっても意図したとおりに動いてくれないからasync/awaitなど工夫が必要だ。

まず、下記の記事を参考にwasm-pack build --target webでpkgディレクトリにwasmファイルができたところまで確認する。

ここで生成されたpkgディレクトリに適当なJSONファイルを置く。

monster.json
{
    "monsters":[
        {"name":"ピカチュウ","value":10},
        {"name":"イーブイ","value":8}
    ]
}

参考記事のlib.rsを、こんな感じに書き換えて、into_serde()でMonsters型に取り込み、最もvalueが大きいモンスターの値をMonster型で出力する。

lib.rs
use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};

# [derive(Serialize, Deserialize)]
pub struct Monster {
    name: String,
    value: usize
}

impl Monster{    
    fn new() -> Self {
        Monster {name: String::new(), value: 0} // 名前のない怪物を生成
    }
    pub fn set_monster(&mut self, name: String, value: usize){
        self.name = name;
        self.value = value;
    }
}

# [derive(Serialize, Deserialize)]
pub struct Monsters {
    monsters: Vec<Monster>
}

# [wasm_bindgen]
pub fn return_max_monster(val: &JsValue) -> JsValue {
    let monsters: Monsters = val.into_serde().unwrap();
    let mut max_monster = Monster::new();
    for monster in monsters.monsters {
        if monster.value > max_monster.value {
            max_monster.set_monster(monster.name,monster.value);
        }
    }
    JsValue::from_serde(&max_monster).unwrap()
}

続けてVueでwasmとの入出力を書く。htmlではボタンのみ用意する。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>hello-wasm example</title>
  </head>
  <body>
    <div id="app">
      <input v-on:click="returnMaxMonster" type="button" value="Max">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="monster.js" type="module"></script>
</body>
</html>

monster.jsで(プロジェクト名).jsをimportする。(自分の場合はcargo new --lib wasmでプロジェクトを作ったので、wasm-pack build --target webでpkgディレクトリにwasm.jsが生成されている)

async/awaitでwasmのモジュールを初期化してからnew Vue()して、lib.rsで書いたreturn_max_monster()を呼び出す。

monster.js
import * as mod from "./wasm.js";
(async () => {
    await mod.default();
    var app = new Vue({
      el: '#app',
      data: {
        monsters: null,
      },
      mounted: function(){
        axios.get("./monster.json").then(
            response => ( this.monsters = response.data )
        );
      },
      methods:{
        returnMaxMonster: function(){
          let s = mod.return_max_monster(this.monsters);
          alert(s.name);
        }
      }
    })
})();

ここまで書けたら、サーバを立ち上げて画面上のボタンをクリックしたらJSONがwasmで処理され、最も値が大きいモンスターの名前が表示される。

スクリーンショット 2020-08-10 12.06.56.png

この仕組みを使って、ドラクエウォークのモンスターの最適な組み合わせを計算するサイトを作ったので、参考にしていただきたい。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?