wasm-bindgenでHello,Worldできたという記事は多いが、wasmを本格的に扱うならVue.jsでJSONをやりとりするところまでテンプレにしておきたい。wasmのモジュールを読み込む前にvar app = new Vue()をやっても意図したとおりに動いてくれないからasync/awaitなど工夫が必要だ。
まず、下記の記事を参考にwasm-pack build --target webでpkgディレクトリにwasmファイルができたところまで確認する。
ここで生成されたpkgディレクトリに適当なJSONファイルを置く。
{
"monsters":[
{"name":"ピカチュウ","value":10},
{"name":"イーブイ","value":8}
]
}
参考記事のlib.rsを、こんな感じに書き換えて、into_serde()でMonsters型に取り込み、最もvalueが大きいモンスターの値をMonster型で出力する。
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ではボタンのみ用意する。
<!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()を呼び出す。
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で処理され、最も値が大きいモンスターの名前が表示される。
この仕組みを使って、ドラクエウォークのモンスターの最適な組み合わせを計算するサイトを作ったので、参考にしていただきたい。