$30 off During Our Annual Pro Sale. View Details »

WebAssembly by Rust

森建
February 19, 2019

WebAssembly by Rust

森建

February 19, 2019
Tweet

More Decks by 森建

Other Decks in Programming

Transcript

  1. WebAssembly by Rust
    明日からプロダクトに使える WebAssembly
    pixiv Inc.
    森内 建太
    2019.2.19

    View Slide

  2. 2
    自己紹介
    ● 主にフロントエンドエンジニア
    ● Ruby on Rails、iOS アプリ開発もやる
    ● ECMAScript とか DOM API とかの仕様まわりを調
    べるのが好き
    ● 今好きな HTTP レスポンスヘッダは Report-To
    petamoriken
    福岡オフィスプロジェクト
    エンジニア

    View Slide

  3. WebAssembly とは
    3

    View Slide

  4. 4
    ● アセンブリではないバイナリ形式(32bit)
    ● ブラウザでなくても実行できる
    ○ モダンブラウザ Chrome / Firefox / Safari / Edge で扱える
    ○ Node.js v8 以降で使える(AWS Lambda, BigQuery...)
    ● JavaScript から WebAssembly を呼ぶインターフェースも定義されている
    ○ 初期化時に函数などの受け渡しが可能(後述)
    WebAssembly とは

    View Slide

  5. シンプルな例
    5
    #[no_mangle]
    pub extern "C" fn succ(x: i32) -> i32 {
    x + 1
    }
    const { instance } = await WebAssembly.instantiateStreaming(fetch("foo.wasm"));
    const exports = instance.exports;
    console.log(exports.succ(42)); // 43

    View Slide

  6. 函数の受け渡しの例
    6
    extern {
    fn console_log(x: i32);
    }
    #[no_mangle]
    pub extern "C" fn succ_log(x: i32) {
    unsafe { console_log(x + 1); }
    }
    const imports = { env: { console_log: console.log } };
    const { instance } = await WebAssembly.instantiateStreaming(fetch("foo.wasm"), imports);
    const exports = instance.exports;
    exports.succ_log(42); // console.log(42 + 1)

    View Slide

  7. 7
    ● 受け渡す函数は引数で数値型(
    i32, i64, f32, f64)のみ扱える
    ● その他受け渡せるもの
    ○ Memory
    ■ WebAssembly で使われるヒープ。バッファを渡したいときにはこれに積んでか
    らその先頭ポインタ(i32 と同等)を函数に渡す
    ○ Table (今のところ Function Table のみ)
    ○ Global Variable (数値型のみ。Chrome, Firefox のみ対応)
    初期化時の受け渡しについて

    View Slide

  8. バッファの受け渡しの例
    8
    use std::{mem, alloc as std_alloc};
    #[no_mangle]
    pub unsafe extern "C" fn alloc(size: usize) -> *mut u8 {
    let layout = std_alloc::Layout::from_size_align(size, mem::align_of::()).unwrap();
    std_alloc::alloc(layout)
    }
    #[no_mangle]
    pub unsafe extern "C" fn dealloc(ptr: *mut u8, size: usize) {
    if size == 0 { return }
    let layout = std_alloc::Layout::from_size_align_unchecked(size, mem::align_of::());
    std_alloc::dealloc(ptr, layout)
    }

    View Slide

  9. バッファの受け渡しの例
    9
    const { instance } = await WebAssembly.instantiateStreaming(fetch("foo.wasm"));
    const exports = instance.exports;
    const ptr = exports.alloc(8);
    new Uint8Array(exports.memory.buffer).set([0, 1, 2, 3, 4, 5, 6, 7], ptr);
    exports.foo(ptr, 8);
    exports.dealloc(ptr, 8);
    use std::slice;
    #[no_mangle]
    pub unsafe extern "C" fn foo(ptr: *const u8, size: usize) {
    let buf = slice::from_raw_parts(ptr, size);
    // ...
    }

    View Slide

  10. wasm-bindgen
    10

    View Slide

  11. 11

    View Slide

  12. 12
    ● Rust (WebAssembly) と JavaScript 間のラッパー
    ● JavaScript の函数の型を書くとインポートしてくれるし、
    String 型の変換もする
    ○ 多くの JavaScript の型が Rust 上では JsValue という型になる
    ■ Optional unwrap 祭りになってそれはそれで辛い
    ● 標準函数は自動でインポートすることが出来る(力技)
    ○ js-sys
    ■ ECMAScript の函数を全て Rust でラップするクレート
    ○ web-sys
    ■ DOM API の函数を全て(ry
    wasm-bindgen とは

    View Slide

  13. 13
    ● JavaScript をラップするだけではなく TypeScript の型ファイルも作ってくれる
    ● wasm-pack
    ○ package.json を吐き出すので npm にそのまま publish 出来る
    ○ wasm-pack-plugin を使うと webpack であたかも普通のモジュールかのように扱
    える
    Rust における wasm-bindgen と wasm-pack と cargo-web と stdweb の違い
    https://qiita.com/legokichi/items/5d6344314ab6d6633554
    wasm-bindgen とは

    View Slide

  14. 14
    ● Rust で書く WebAssembly はもうプロダクトに使えそう
    ○ wasm-bindgen (web-sys) を使うと DOM API にアクセスすることが出来るがあまり
    メリットはない
    ○ 要所での重い処理(バッファの変換とか)に向いている
    ■ WebP のデコードとか
    詳しくは個人の Scrapbox にまとめてますので興味があれば
    https://scrapbox.io/petamoriken/WebAssembly_by_Rust
    まとめ

    View Slide