Web­Assemblyが気になったのでRustで試してみた

こんにちは、コバヤシです。
Web­Assemblyって知っていますか?
何かと目にする機会も多くなってきたので、今更感も強いですがRustを使ってWeb­Assemblyを試してみたいと思います。

Web­Assemblyとは

WebAssemblyはWebブラウザーが実行できるバイナリー形式の言語です。
Rustなどの言語で書かれたプログラムをコンパイルして実行します。
コンパイル済みなのでJavaScriptより高速に動作。
現在のところJavaScriptを置き換えるものではなく互いにサポートし合うというのが狙いのようです。

使い所としては、画像やビデオの編集などの計算量の多い処理をWeb­Assemblyで書かれたプログラムで処理させるなどが考えられます。

Rustとは

Rustは2006年に開発が始まった新しいオープンソースのプログラミング言語です。
高い安全性や高パフォーマンスからC/C++に置き換わる言語として注目されおり、
MicrosoftはWindowsの開発にRustを採用していることを公表しています。

www.rust-lang.org

今回はこのRustを使ってWeb­Assemblyを作成していきます。

Rustのインストール

Macの環境でインストールしていきます。

brew install rustup-init

brewで簡単にインストール出来ます。
インストールが出来たら初期化します。

rustup-init

warning: it looks like you have an existing installation of Rust at:
warning: /usr/local/bin
warning: rustup should not be installed alongside Rust. Please uninstall your existing Rust first.
warning: Otherwise you may have confusion unless you are careful with your PATH
warning: If you are sure that you want both rustup and your already installed Rust
warning: then please reply `y' or `yes' or set RUSTUP_INIT_SKIP_PATH_CHECK to yes
warning: or pass `-y' to ignore all ignorable checks.
error: cannot install while Rust is installed

何やらエラーがでました。
Rustが入っているというエラーなのでRustを削除します。
(以前お試しで入れたような記憶が。。)

brew uninstall rust

アンインストールが出来たら再度実行します。

brew uninstall rust
  
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1

初期化が終わったら設定を反映します。

source "$HOME/.cargo/env"

インストールできたのか確認します。

rustup --version
  
rustup 1.25.2 (2023-02-01)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.67.1 (d5a82bbd2 2023-02-07)`

無事インストール出来たようなのでプロジェクトを作成して実行してみます。

cargo new hello
cd hello
cargo run

Compiling hello v0.1.0 (/xxxx/xxx/xxxx/xxxx/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.89s
     Running `target/debug/hello`
Hello, world!

無事に表示されました。

Web­Assemblyを作成する

実際にWeb­Assemblyを作成していきます。

まずWeb­Assembly(wasm)をビルドするためのパッケージをインストールします。
※Web­Assemblyのファイル形式にはwasm形式とwat形式があります。
バイナリ形式がwasm、人が読める形の中間ファイルがwat形式です

cargo install wasm-pack

プロジェクトをライブラリのプロジェクトとして作成します。

cargo new --lib hello-wasm

プロジェクトが出来たら
src/lib.rsを以下のように書き換えます。

use wasm_bindgen::prelude::*;
  
#[wasm_bindgen]
extern {
    pub fn alert(s: &str);
}
  
#[wasm_bindgen]
pub fn say(name: &str) {
    alert(&format!("Hello, {}!", name));
}

「use wasm_bindgen::prelude::*;」でJavaScriptとRustを繋ぐモジュール(Rustではクレートと呼ばれる)を読み込んでいます。

externで使用したいJavaScriptの命令を記述。
pub fnで、JavaScript側から呼び出してもらう命令を記述します。

次は、ビルドですが
その前にCargo.tomlを編集して設定を書き換えます。
実際は[package]部分も書き換える必要があるのですが今回は割愛します。

[package]
name = "hello-wasm"
version = "0.1.0"
edition = "2021"
  
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
  
[dependencies]
wasm-bindgen = "0.2" <= 追記
  
[lib] <= 追記
crate-type = ["cdylib"] <= 追記

targetをwebにしてビルドをします。

wasm-pack build --target web

ビルドをすると「pkg」ディレクトリが作成されるので、これをwebの公開ディレクトリに配置します。
そして、このpkgをjavascriptから読み込みます。
scriptタグでタイプをmoduleとして記述するのがミソです。

<body>
  <script type="module">
    import init, {say} from "./pkg/hello_wasm.js";
    init()
      .then(() => {
        say("World")
      });
  </script>
</body>

ページを読み込むとアラートが表示されました。

JavaScriptからRustで書いた命令が実行出来て、Rust側からJavaScriptのアラートが実行出来ています。
不思議な感じがしますが面白いですね。

まとめ

今回はアラートだけでしたが、実際はJavaScriptでは荷が重い処理をさせた時に真価が発揮されます。 今後もRustを含め勉強していきたいと思います。