SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Rust言語で作るWebバイナリファイル「WebAssembly」入門

Rust/WebAssemblyとJavaScriptのデータ交換を使いこなす!

Rust言語で作るWebバイナリファイル「WebAssembly」入門 第4回

  • X ポスト
  • このエントリーをはてなブックマークに追加

wasm_bindgenの利用方法をコードと共に解説!

 以下では、wasm_bindgenについて、より詳しく説明していきます。

wasm_bindgenに指定できる属性

 wasm_bindgenは属性を指定することでさまざまな形式のデータ交換を実現できます。この方法を、図2のサンプルで説明します。名前を入力してボタンをクリックすると挨拶文が表示されます。「こんにちは」の挨拶文はconsole.logにも出力されます。

図2 wasm_bindgenに属性を指定して実装したサンプル(p002-bindgen-simple)
図2 wasm_bindgenに属性を指定して実装したサンプル(p002-bindgen-simple)

 「こんにちは」のJavaScript実装はリスト3の通りです。(1)でテキストボックスから名前の文字列を取得して、それを(2)でRust/WebAssemblyに渡して処理を実行し、挨拶文を取得します。取得した挨拶文は(3)で画面に表示します。

[リスト3]「こんにちは」ボタンクリック時に実行されるJavaScript実装(p002-bindgen-simple/www/index.js)
// inputから名前の文字列を取得 ...(1)
const name = document.getElementById('name-input').value;
// Rust/WebAssemblyで実装したメソッドで挨拶文を取得 ...(2)
const greet = wasm.get_greet_text(name);
// 挨拶文を画面に表示 ...(3)
document.getElementById('greet-text').textContent = greet;

 リスト3に対応するRust/WebAssembly側の実装はリスト4の通りです。

[リスト4]リスト3に対応するRustの実装(p002-bindgen-simple/src/lib.rs)
// console.logを参照 ...(1)
#[wasm_bindgen]
extern {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}
// 挨拶文を作成して返却 ...(2)
#[wasm_bindgen]
pub fn get_greet_text(name: &str) -> String {
    let greet_text = format!("こんにちは、{}さん!", name);
    log(&greet_text);   // console.logにも出力
    return greet_text;
}

 (1)はJavaScriptのconsole.logメソッドをRust/WebAssemblyから実行する記述です。js_namespace属性で、メソッドが含まれる名前空間(ここではconsole)を指定できます。(2)は、JavaScriptから呼ばれるget_greet_textメソッドの実装で、挨拶文を作って、logメソッドでconsole.logへ出力しつつ返却します。なおlogメソッドの引数に「&greet_text」と&がついているのは、文字列をStringから&strに変換する指定です。

 一方、「こんばんは」のJavaScript実装はリスト5の通りです。(1)はリスト3と同じですが、取得した挨拶文を(2)のwasm.apply_greet_textメソッドに渡して実行します。

[リスト5]「こんばんは」ボタンクリック時に実行されるJavaScript実装(p002-bindgen-simple/www/index.js)
// inputから名前の文字列を取得 ...(1)
const name = document.getElementById('name-input').value;
// Rust/WebAssemblyで実装した挨拶文表示処理を実行 ...(2)
wasm.apply_greet_text(name);

 リスト5に対応するRust/WebAssembly側の実装はリスト6の通りです。

[リスト6]リスト5に対応するRustの実装(p002-bindgen-simple/src/lib.rs)
// exports.jsからapplyGreetTextメソッドを参照 ...(1)
#[wasm_bindgen(module = "/www/exports.js")]
extern {
    fn applyGreetText(s: &str);
}
// 挨拶文を作成してJavaScriptのapplyGreetTextに渡す ...(2)
#[wasm_bindgen]
pub fn apply_greet_text(name: &str) {
    let greet_text = format!("こんばんは、{}さん!", name);
    applyGreetText(&greet_text);
}

 (1)は/www/exports.jsに含まれるapplyGreetTextメソッド(文言を画面に表示する処理)をRust/WebAssemblyから実行する記述です。wasm_bindgenのmodule属性で、メソッドが含まれるモジュールを指定できます。(2)では、作成した挨拶文を(1)のapplyGreetTextメソッドに渡して、画面に表示します。

 wasm_bindgenに指定できる全ての属性については、公式ドキュメントも参考にしてください。

Rustの構造体をJavaScriptのオブジェクトとして渡す

 wasm_bindgenでは、Rustで実装した構造体を、JavaScriptのオブジェクトとして参照することもできます。図3のサンプルでは、内部に整数の数値を持ったカウンターのオブジェクトをRust/WebAseemblyで実装し、それをJavaScriptから操作します。

図3 Rustの構造体をJavaScriptから参照するサンプル(p003-bindgen-struct)
図3 Rustの構造体をJavaScriptから参照するサンプル(p003-bindgen-struct)

 Rustで実装したカウンターの構造体(RustStructCounter)は、リスト7の通りです。

[リスト7]RustStructCounter構造体(p003-bindgen-struct/src/lib.rs)
// Rustの構造体をJavaScriptにエクスポート ...(1)
#[wasm_bindgen]
pub struct RustStructCounter {
    counter: u32
}
// Rust構造体のメソッドをJavaScriptにエクスポート ...(2)
#[wasm_bindgen]
impl RustStructCounter {
    // 構造体を生成 ...(3)
    pub fn new(init_value: u32) -> RustStructCounter {
        // counterの初期値を設定しつつ、RustStructCounterを生成
        return RustStructCounter {
            counter: init_value
        }
    }
    // カウンターをリセット ...(4)
    pub fn reset_value(&mut self) {
        self.counter = 0;
    }
    // カウンターを1増やす ...(5)
    pub fn add_value(&mut self) {
        self.counter += 1;
    }
    // 現在のカウンター値を取得 ...(6)
    pub fn get_value(&mut self) -> u32 {
        return self.counter;
    }
}

 (1)で、u32(符号なし32ビット整数)型のcounterを持つRustStructCounter構造体を定義します。Rustの構造体には、(2)のimplキーワードによりメソッドを実装できます。(3)は構造体を生成する処理で、引数で受け取ったinit_valueで内部のcounterを初期化しつつ、構造体を返却します。(4)(5)(6)はカウンター値の操作・取得を行う処理です。メソッドの第1引数に渡される構造体への参照を利用して処理を行います。

 対応するJavaScript側の処理はリスト8です。

[リスト8]RustStructCounter構造体をJavaScriptで利用する実装(p003-bindgen-struct/www/index.js)
// RustStructCounterをインポート ...(1)
import { RustStructCounter } from 'p003-bindgen-struct';
// カウンター値を表示する処理 ...(2)
function applyCounterValue() {
  document.getElementById('counter-value').textContent = counter.get_value();
}
// RustStructCounterを生成 ...(3)
const counter = RustStructCounter.new(5);   // 生成(初期値:5)
applyCounterValue();                        // 画面に反映
// 追加ボタンの処理 ...(4)
document.getElementById('add-button').addEventListener('click', () => {
  counter.add_value();    // カウンターを追加
  applyCounterValue();    // 画面に反映
}, false);
// リセットボタンの処理 ...(5)
document.getElementById('reset-button').addEventListener('click', () => {
  counter.reset_value();  // カウンターをリセット
  applyCounterValue();    // 画面に反映
}, false);

 (1)で、リスト7の実装からRustStructCounterをJavaScriptにインポートします。(2)はカウンター内容を画面に表示する処理で、RustStructCounterから生成したオブジェクトcounterのget_valueメソッドでカウンターの値を取得して画面に表示します。

 (3)で、RustStructCounter.newメソッドを利用して、RustStructCounter構造体をJavaScriptオブジェクトcounterとして、初期値5を与えつつ生成します。追加ボタンの処理(4)ではcounter.add_valueメソッドを実行してカウンターを増やし、リセットボタンの処理(5)ではcounter.reset_valueメソッドを実行してカウンターを0に戻しています。

次のページ
大きなデータはJavaScriptからRust/WebAssemblyのメモリに直接アクセス

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Rust言語で作るWebバイナリファイル「WebAssembly」入門連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト  吉川 英一(ヨシカワ エイイチ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/16904 2022/12/12 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング