ブラウザで動作するクライアント側がサポートする2つの言語、JavaScriptとWebAssembly。 最近のお気に入り、静的型付け言語 Rust は WebAssembly のバイトコードを生成してくれます。 (もう一つの人気の静的型付け言語TypeScriptは、動的型付け言語JavaScriptへと変換するトランスパイラ。GLSLを含めると3つ?)
早速実験してみましょう。
まず準備、Rustをインストールし、WebAssembly用にコンパイルするために、targetを追加します(一度だけでok)
$ rustup target add wasm32-unknown-unknown 次のコードは、超コンパクトな、足し算するだけのRustのプログラム add.rs です。
#![no_main] #![no_std] #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } #[no_mangle] pub fn add(a: i32, b: i32) -> i32 { a + b }
mainがなく、標準ライブラリを使わないための設定をするのは、IchigoJam用のRust「rust4ij」と同様です。 no_mangleで、最適化して行方不明になってしまわないよう設定します。
コンパイルはこのように
$ rustc --target wasm32-unknown-unknown add.rs -C opt-level=1
131byte、小さな add.wasm ファイルができました!
(wasm-strip add.wasm で116byteに!opt-level=1 を付けないとデバッグ情報で1.5MBに!)
wasmをJavaScriptから呼び出すのはこんなコードを書きます。
<script type="module"> (async () => { const bin = await (await fetch("./add.wasm")).arrayBuffer(); const wasm = await WebAssembly.instantiate(bin); const ex = wasm.instance.exports; const add = ex.add; document.body.textContent = "WebAssembly in Rust, add(1,2) = " + add(1, 2); })(); </script>
* ブラウザがトップレベルawaitに対応してくれると、async関数で囲む必要がなくなります
* SafariがWebAssembly.instantiateStreaming対応したらもっと短くかけます
wasmの読み込みはファイル上ではだめなので、live-serverなど、何かHTTPサーバーをローカルに立てて、http://127.0.0.1:8080/ などでアクセスするか、手持ちのサーバーにアップして試してみましょう!
$ live-server
コンパクトで簡単ですね!
JavaScriptやブラウザとの相互やり取りには共有メモリを使うイメージで連携します。
本格的なwebアプリ、RustとJavaScriptの連携で一度作ってみたいと思います。
DenoやNode.jsでもwasmは動きます。
$ deno run -A test-file.mjs $ node test-node.mjs
src on GitHub、いろいろ遊んでみてください!
links
- マシン語で検証、RustはC言語の代わりになりうるか? IchigoJamでライトに楽しむ組み込み開発 panic編と情報処理
- IchigoJamでかんたん組み込みRust開発 - rust4ij x IchigoJam API