6
1

More than 1 year has passed since last update.

UUID生成で入門するRustでWebAssembly

Last updated at Posted at 2022-12-01

はじめに

本記事はProgaku Advent Calendar 2022 2日目担当です。
みなさん、WebAssembly(以下wasm)はご存知でしょうか? MDNのWebAssemblyに書かれている通り、簡単に言うとコンパイル済みのバイナリファイルをブラウザ上で実行できる技術です。
ますます高まるwebアプリケーションへの要求に対して、wasmの技術は必要なものになってくると推測できます。
そういうのもありアドベントカレンダーのいい機会でもありますので、アウトプットも兼ねて触れてみました。
よろしくお願いします。

目的

タイトル通り。Rustで書かれたUUID生成処理をwasmでTypeScriptから動かします。

環境

  • M1 Mac
  • npm v8.5.0
  • rustc v1.65.0

環境構築

Rustサイド

install

$ brew install rustup-init
$ rustup-init
$ rustup target add wasm32-unknown-unknown

確認します。

$ rustup --version
$ rustc --version
$ cargo --version

必要ツールのインストールとプロジェクトの作成を行います。

$ cargo isntall wasm-bindgen
$ cargo new --lib wasm

TypeScriptサイド

$ npm init -y
$ npm install ts-node
$ npx tsc --init

ts-nodeで動作を確認します。
tsconfigは生成時そのままでも構いません。

プロダクト

ディレクトリ構造

名前もディレクトリ構造も雑ですが目をつぶってください。

.
├── apps
│   └── main.ts
├── node_modules
│   └── ...
├── package-lock.json
├── package.json
├── tsconfig.json
└── wasm
    ├── Cargo.lock
    ├── Cargo.toml
    └── src
        └── lib.rs

Rustサイド

Cargo.toml

Cargo.toml に以下の通り記載します。

[package]
name = "wasm"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib"]

[dependencies]
serde = "1.0.147"
serde_json = "1.0.89"
uuid = { version = "1.2.2", features = ["v4", "serde"] }
wasm-bindgen = "0.2.83"
getrandom = { version = "0.2", features = ["js"] }

uuidの生成はCrate uuidを用います。
これをwasmで使うには getrandom が必要になるため加えています。

参考: Usage with wasm-pack?

JSONパッケージがある理由は後述します。

実装

wasm/src/lib.rs に記載します。

use uuid::Uuid;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {}

#[wasm_bindgen]
pub fn uuid(n: i32) -> String {
    let mut uuids = vec![];
    for _ in 0..n {
        uuids.push(Uuid::new_v4().to_string());
    }
    return serde_json::to_string(&uuids).unwrap();
}

wasmではVec型を return できないのでjsonでダンプします。これがJSONパッケージを入れる理由となります。
せっかくなので引数も取れるようにしました。UUIDの生成数を与えます。

参考: wasmのRustではVec型をreturnできない

build

$ wasm-pack build --target nodejs

今回はts-nodeで動作確認をするため、ターゲットを nodejs とします。

参考: ビルドターゲット

TypeScriptサイド

apps/main.ts

import { uuid } from '../wasm/pkg/wasm';

const wasmUuid = uuid(10)

console.log(wasmUuid);
/**
* '[
*   "c7a2db39-4343-450e-bd99-8f8e33336260",
*   "5701aa3a-ffbe-435d-9fe5-d90903d99378",
*   "2086290a-c118-4e50-8270-368884fcf874",
*   "e466230f-428e-4305-b370-9f5314af95fb",
*   "b4c642ce-c47a-4940-a81a-bc1d115b711c",
*   "e7c556ef-3c90-4f73-8e10-e71c44fae295",
*   "32ad87c1-0fd9-4884-9756-919ae22dc71a",
*   "a0c12d0b-11f5-4d5b-bfdc-e1b70cf249ad",
*   "d0632205-ab34-4575-96df-20fb65638a01",
*   "174dbdd3-9840-4d0e-b623-e8d30d1142ab"
* ]'
*/
console.log(typeof wasmUuid);  // string

返却値は見やすいように整形してあります。また、importは上に記載したディレクトリ構造での相対パスとなっております。ご注意ください。
上記の通り、wasmサイドからの返却値はstring型になっているため、 JSON.parse()をするなどして扱いましょう。

おわりに

読んで頂きありがとうございました。
今はwasmといえばRustかC++が真っ先に上がるかと思いますが、RubyKotlinもwasm技術に進出しています。
現在wasmを学ぶにあたって情報が多いのがRustだったためRustを選択しましたが、今後は得意な言語で書けるようになるでしょう。
先を見据えて今のうちに触れておくのも生存戦略としてもありかもですね。
以上、Progaku Advent Calendar 2022 2日目でした。

参考

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1