Open5
WebAssembly(Rust)入門
WebAssemblyとは
「Web上でネイティブアプリばりの高速処理ができるようにバイナリコードを実行する仕組み」
であるとざっくりとした認識で今はOKとします。
より深く知りたい人は、見出しの青い文字がリンクになっているので、リンク先のMDN docsのページを読んでいただければと思います。
開発環境を整えよう
Rustの導入(devcontainerを使う)
DevContainerは
- devcontainer.json
- Dockerfile
- compose.yaml
などを記述して、それを使って環境構築をするのだが、書くのがめんどくさかったので
このリポジトリをクローンして使うことにするRustのライブラリプロジェクト(WebAssemblyを書くプロジェクト)を作成
cargo new --lib [library-name]
wasm-pack
とwasm-bindgen
を導入
cargo install wasm-pack && cargo add wasm-bindgen
コードを書く
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
ビルドする
wasm-pack build --target web
出力されたファイルについて
-
[library-name]_bg.wasm
WebAssembly本体 -
[library-name]_bg.wasm.d.ts
Rustで定義した関数のプロトタイプ宣言があるファイル -
[library-name].d.ts
Webブラウザ上にあるWebAssemblyを扱うAPIの形式に合わせた型定義ファイル
-
[library-name].js
これもWebブラウザ上にあるWebAssemblyを扱うAPIの形式に合わせたjsファイル
wasm内の、Rustで定義したい関数を呼び出す文があるのと、WebAssemblyに関するWebブラウザのAPIを使っているところを見ると、実際のところ触るファイルはこれなんじゃないか
実際に使う
<script type="module">
import init,{add} from "./pkg/[library_name].js"
init().then(() => {console.log( add(1,3) )})
</script>
すると、DeveloperToolのConsoleに4と表示される
ステップアップ(DOM操作)
web-sys
を導入
cargo add web-sys
コードを書く
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn draw() {
let window = web_sys::window().unwrap();
// web_sys::window()はOption<Window>を返すのでunwrap()で取り出す
let document = window.document().unwrap();
// window.document()はOption<Document>を返すのでunwrap()で取り出す
let canvas_el_unwrap = document.get_element_by_id("canvas").unwrap();
// document.get_element_by_id()はOption<Element>を返すのでunwrap()で取り出す
let canvas: web_sys::HtmlCanvasElement = canvas_el_unwrap.dyn_into()::<web_sys::HtmlCanvasElement>.unwrap();
// dyn_into()で型変換を行う
let context_unwrap = canvas.get_context("2d").unwrap().unwrap();
// canvas.get_context()はOption<Result<CanvasRenderingContext2d, JsValue>>を返すのでunwrap()で取り出す
let context: web_sys::CanvasRenderingContext2d = context_unwrap.dyn_into()::<web_sys::CanvasRenderingContext2d>.unwrap();
context.move_to(300.0, 0.0);
context.begin_path();
context.line_to(0.0, 600.0);
context.line_to(600.0, 600.0);
context.line_to(300.0, 0.0);
context.close_path();
context.stroke();
context.fill();
Ok(())
}
以下の14Pに記載されているコードを少し改変したもの
Smith, E. (2023). RustとWebAssemblyによるゲーム開発─安全・高速・プラットフォーム非依存のWebアプリ開発入門─ (初版). 株式会社オライリー・ジャパン.