WebAssembly by Rust
参考サイト
ワーキンググループ。これを追ってたら間違いない。
WebAssembly に関連するクレートがまとめてある。
wasm-bindgen を使った開発ではこちらの記事を参考にすると良い。
Fukuoka.rs vol.2 で自分が発表した資料と wasm-bindgen, wasm-pack (wasm-pack-plugin) の簡単な例が見れる。
情報が古いが、参考になるかもしれない。
プロジェクト環境
cargo
code:cargo.toml
name = "wasm-test"
version = "0.1.0"
edition = "2018"
publish = false
code:.cargo/config (toml)
target = "wasm32-unknown-unknown"
もし nightly を使いたい場合は rls や clippy が不安定なため、rustup-components-history を見て使えそうな toolchain に固定する必要がある(実験的な実装を使う必要がなければ stable でよい)。 code:.cargo/rust-toolchain
nightly-2019-01-19
rls (rls-vscode)
code:.vscode/settings.json
{
"rust.target": "wasm32-unknown-unknown",
"rust.all_targets": false
}
clippy を使う場合はあらかじめ rustup component add clippy しておく。
関連するクレート(モジュール)
WebAssembly の固有の組み込み機能を呼ぶときに使う。memory.grow はもちろんのこと Nightly 環境では Threads や SIMD も試すことが出来る。 WebAssembly で使えるアロケータ。global_allocator として使える。これを入れなかった場合は dlmalloc がデフォルトとして使われてそう。 js-sys の DOM API 版。
wasm-binding によって作られた WebAssembly と JavaScript のラッパーコードから package.json を生成して、そのまま npm publish することが出来るようにするライブラリ。Node.js で使えるのはもちろんのこと、wasm-pack-plugin を使うと webpack であたかも普通のモジュールかのように扱えるように出来る。プロダクト用途に便利。 Example
一番シンプルなやつ(allocate)
code: (rs)
use std::{mem, alloc as std_alloc};
pub unsafe extern fn alloc(size: usize) -> *mut u8 {
let layout = std_alloc::Layout::from_size_align(size, mem::align_of::<usize>()).unwrap();
std_alloc::alloc(layout)
}
pub unsafe extern fn dealloc(ptr: *mut u8, size: usize) {
if size == 0 { return }
let layout = std_alloc::Layout::from_size_align_unchecked(size, mem::align_of::<usize>());
std_alloc::dealloc(ptr, layout)
}
JavaScript の函数を呼ぶ
code: (rust)
extern {
fn console_log(num: f64);
}
code: (js)
const imports = { env: { console_log: console.log } };
WebAssembly.instantiate(buffer, imports);
no_std + wee_alloc (nightly)
no_std 環境では core クレートを使うことになるが core クレートには alloc が入っておらず、alloc クレートを使う。
core クレートには Cursor がないのでだいぶ厳しい。一応 core_io クレートに逃げることはできる。WebAssembly 向けでは std が使えるためあまり気にしなくて良さそう。 code: (rs)
extern crate alloc;
pub fn panic(_info: &::core::panic::PanicInfo) -> ! {
unsafe {
::core::intrinsics::abort();
}
}
pub extern fn oom(_: ::core::alloc::Layout) -> ! {
unsafe {
::core::intrinsics::abort();
}
}
// Needed for non-wasm targets.
pub extern fn eh_personality() {}
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
use core::mem;
use alloc::alloc as sys_alloc;
pub unsafe extern fn alloc(size: usize) -> *mut u8 {
let layout = sys_alloc::Layout::from_size_align(size, mem::align_of::<usize>()).unwrap();
sys_alloc::alloc(layout)
}
pub unsafe extern fn dealloc(ptr: *mut u8, size: usize) {
if size == 0 { return }
let layout = sys_alloc::Layout::from_size_align_unchecked(size, mem::align_of::<usize>());
sys_alloc::dealloc(ptr, layout)
}
その他設定
code: .cargo/config (toml)
target = "wasm32-unknown-unknown"
rustflags = [
"-C", "link-arg=--import-memory",
]
もしくは nightly 環境だと link_args attribute を使って以下のように指定することも出来る。
code:lib.rs