Closed10

Tutorial - Rust and WebAssembly をやってみる

monaqamonaqa

This tutorial is for anyone who already has basic Rust and JavaScript experience, and wants to learn how to use Rust, WebAssembly, and JavaScript together.
You should be comfortable reading and writing basic Rust, JavaScript, and HTML. You definitely do not need to be an expert.

うっ(JavaScript 大丈夫かな)

monaqamonaqa

セットアップ

  • Rustツールチェイン
  • wasm-pack
    • リンク先のインストールスクリプトは現状まだ M1 Mac をサポートしていないらしい。
    • かわりに cargo install wasm-pack で入れた。とりあえずすんなり入った
  • cargo-generate
  • npm (latest)

所感: cargo やっぱ好き

monaqamonaqa

Hello, World!

特に問題なし。 package.json の中身が例と若干違った点が気になるぐらい。

{
  "files": [
    "wasm_game_of_life_bg.wasm",
    "wasm_game_of_life.js",
    "wasm_game_of_life_bg.js",
    "wasm_game_of_life.d.ts"
  ],
}

いきなり様々なファイルが登場したが、とりあえず localhost:8080 で動かすところまではできた。
演習問題も自力でいけたのでここは良しとする。

疑問

  • www ディレクトリ内にも .git/ があるためにサブもジュール扱いになるのだけど、これは実際にはどう管理するのだろう。
  • 演習では greet() が1つの引数を取るように実装が変更されるのだが、ここで JS/TS 側で greet() 関数を呼び出すときに引数を指定しなくてもコンパイルエラーにならなかった。Compile とログには出てくるが、 TS のような静的解析は行わないということだろうか。
    • ちなみにこのとき、開発者ツールのコンソールを開いてみると実行時にエラーが起きていることが分かる(ただ、エラーの内容はあんまり分かりやすいとは思えなかった。単に JS の経験不足かも)
monaqamonaqa

Implementing Conway's Game of Life

Interfacing Rust and JavaScript

この節はとても重要らしいので、ちゃんと要点をまとめておこう。

  • JS の garbage-collected heap (GC heap) は WASM (Rust) の線形メモリ空間とは全く異なる場所にアロケートされている
    • WASM は GC heap にアクセスできない(2018 年4月時点)
      • 今後変わるかも
    • 逆に、JS から線形メモリ空間へのアクセスは、スカラー値を要素にもつ ArrayBuffer としてであれば可能
  • wasm_bindgen はこの Rust と JS の垣根を越えるための “common understanding” を定義してくれる
    • 便利!
  • そうはいってもデータのメモリ配置や「垣根」については依然意識しておく必要がある
    • 不要なコピーを少なくする
    • serialize/deserialize を少なくする("opaque handle" なるものを使う?)
    • 一般的には「デカくて長寿命のデータ」は Rust の型として線形メモリに置き、その opaque handle を JS に公開することが多い

ライフゲームでもメモリの問題は重要。ライフゲームの世界 (universe) 全体を、時間経過ごとに総じてコピーしたくはないからね。

Rust Implementation

基本的には書いてある内容をそのまま書き写すので問題なさそう。
実装内容もさして難しくない。

  • うっかり #[wasm_bindgen] attribute を書き忘れないよう注意。
    これを忘れると wasm-pack build しても pkg/wasm_game_of_life.d.ts 等に反映されない。(やらかした)
  • 基本的には「private な関数を書く impl block」と「public に公開する関数を書く impl block(こっちにだけ #[wasm_bindgen] をつける」に分けることになりそう。
  • わざわざ self.to_string() を呼び出すだけの render() 関数を定義しているのも、おそらく to_string() メソッドが JS 側に公開されないからだろう、と推測。まあ render という名前のほうが分かりやすいからというのもあるかも。

Rendering with JavaScript

こちらも実際に書かれている通りに写す。
前の工程で正しい pkg/wasm_game_of_life.d.ts が生成されていれば、ちゃんとメソッド名の補完などが正しくきくようになる。素晴らしい開発体験だ。

ここまで出来るようになると、実際に動くものが見えるようになる。 思ったより早くできた。
インタラクティブに操作出来るようになるのはまだ先の話だが、動くものが見えるとやはり楽しい。

monaqamonaqa

Testing Conway's Game of Life

Rust-generated WebAssembly functions cannot return borrowed references.
Try compiling the Rust-generated WebAssembly with the attribute and take a look at the errors you get.

これは頭の片隅にいれておくとよさそう。#[wasm_bindgen] をつけるメソッドでは、借用を返せない。結構大きな制約だ。「とりあえず #[wasm_bindgen] をつけとく」といった戦略はとれないことが分かる。
(ちょっと気になるのが、 rust-analyzer がこのエラーを検出してくれなかったこと。wasm-pack build でコンパイルして確かめる他なさそう)

テストは書けた。ちょっと引っかかったところがいくつかある。

  • 特にチュートリアルには明記されてなかったが、 use wasm_bindgen_test::*; は必要だった。
    • テンプレートに元から入っていたので、消さなければ良いはず。
  • extern crate ... は無くても動いた。
    • これどういうときに必要なのかいまだに分かってない
  • --chrome--safari などの wasm-pack test 実行時のオプション。
    • テストを実行するブラウザを選択できるらしい。
    • --chrome を試すと Error: chromedriver binaries are unavailable for this target とのエラー。
      • もしかして M1 Mac には対応してなかったりする?
    • --safari で実行するときは、予め Safari ブラウザから「リモートオートメーションを許可」しておく必要があった。以下設定手順:
      1. Safari を開いた状態でメニューバーから Safari -> 環境設定 を開く
      2. 詳細->「メニューバーに"開発"メニューを表示」のチェックボックスをつける
      3. メニューバーに「開発」が表示されるので、そこを選択して「リモートオートメーションを許可」の部分をクリック

とりあえず、 --safari オプションでのテストは実行できた。

  • --headless をつけると自動的にブラウザが立ち上がりテストが実行され自動で閉じる。
  • --headless をつけなければブラウザが立ち上がる。そこから http://127.0.0.1:8000 にアクセスすればテストが実行されるらしい。

まだブラウザとテストの関係がよく分かってないが、ブラウザの上で WASM を動かしているような感じなのだろうか?
とりあえずテストの実行手順は分かったのでよしとしよう。

monaqamonaqa

Debugging

ブレークポイントを敷き、ログを吐いたりブラウザ上で一時停止したりできるようになった。

以下、注意点。

  • 予めブラウザの開発者ツールを開いておいてから localhost:8080 にアクセスする必要がありそう。
    ライフゲームが起動してから開発者ツールを開こうとしても、うまく開けなかった。
monaqamonaqa

Adding Interactivity

書いてある通りに実装すればうまくいく。
ここまで来ると眺めるだけでなくゲームの世界に干渉できるようになるので、普通に遊べる。

monaqamonaqa

残るは

  • Time Profiling
  • Shrinking .wasm size
  • Publishing to npm

だが、このあたりはまた必要になったときにやろう。

このスクラップは2022/03/15にクローズされました