RustとWebAssemblyで、四角いマスの中にランダムな数字を表示する。

環境

rustとwasmの開発環境はdocker。その中に、cargo-generateで wasm-packを利用してプロジェクトを作っています。

Dockerfile

FROM rustlang/rust:nightly
ENV PATH=/usr/local/cargo/bin:$PATH
RUN cargo install wasm-pack && cargo install cargo-generate
RUN set -x \
    && curl -sL https://deb.nodesource.com/setup_11.x | bash - \
    && apt-get install -y nodejs \
    && npm install npm@latest -g

build

docker build -t eg-rust .

run

docker run -it --rm -p 8080:8080 -e USER=$USER -v "$PWD":/usr/src/ -w /usr/src eg-rust /bin/bash

generate project

cargo generate --git https://github.com/rustwasm/wasm-pack-templa
te --name numbers

npm init

cd numbers
npm init wasm-app www
cd www
npm install

実装

Cargo.toml

dependenciesに wasm-bindgen対応の rand を追加

...
[dependencies]
rand = { version = "0.6", features = ["wasm-bindgen"] }
...

src/lib.rs

mod utils;

use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
pub struct NumberMatrix {
    width: u32,
    height: u32,
    numbers: Vec<u8>,
}

use rand::Rng;

#[wasm_bindgen]
impl NumberMatrix {
    pub fn tick(&mut self) {
        let mut rng = rand::thread_rng();
        
        let numbers = (0..self.width * self.height)
            .map(|_i|{
                rng.gen_range(0, 9) as u8
            })
            .collect();
        self.numbers = numbers;
    } 
    
    pub fn new() -> NumberMatrix {
        let width = 32;
        let height = 32;
        let numbers = (0..width * height)
            .map(|_i| { 0 })
            .collect();
        
        NumberMatrix {
            width,
            height,
            numbers,
        }
    }
    
    pub fn width(&self) -> u32 {
        self.width
    } 
    
    pub fn height(&self) -> u32 {
        self.height
    }
    
    pub fn numbers(&self) -> *const u8 {
        self.numbers.as_ptr()
    }
}

www/index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello wasm-pack!</title>
  </head>
  <body>
    <canvas id="mycanvas"></canvas>
    <script src="./bootstrap.js"></script>
  </body>
</html>

www/index.js

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello wasm-pack!</title>
  </head>
  <body>
    <canvas id="mycanvas"></canvas>
    <script src="./bootstrap.js"></script>
  </body>
</html>

webpack.config.js

テスト用にdevServerを入れる。

module.exports = {
  ... 省略 ...
  devServer: {
    host: "0.0.0.0",
    disableHostCheck: true
  }
};

ビルド

(いらないかも)rustupの targetが足りなかったので。

rustup target add wasm32-unknown-unknown

wasm-pack

npm用のライブラリを作ってリンクさせる

wasm-pack build
cd pkg
npm link
cd ../www
npm link numbers

Run

cd www
npm start

こんな感じで数字が表示されて。高速で変わっていけばOK.