令åææ°ç、ã¨ä¸åº¦è¨ã£ã¦ã¿ããã£ãã
å æ¥ãæä½ãã§WASM Componentã®ãã¤ããªãä½ã£ã¦ã¿ããã§ãããmruby/edgeã¯å ¨é¨Rustã§æ¸ãã¦ããã®ã§ãã§ã¯æè¿ã®Rustã§ã¯ã©ãããã¨ãããããã ã£ã¨æ®ãã¨ãã¾ãã
çµè«ãã¡ã¼ã¹ã
ããã«æ¸ãã¦ããéãã§ãããå®ã
ããä¸ã®ä¸å²ã¨cargo-componentãã¼ã¹ã®æé ãå¤ãã£ããããã®ã§ãå°ãã§ãæ°ããæ å ±ãå¤ããããããªã¨æã£ã¦ï¼ãã¨èªåã®ç解ã®ããï¼ããã°ã«æ®ãã¦ããã¾ãã
ãã£ããããæµã
ã¾ãææ°ã®Rustã§ã wasm32-wasip2
targetãã¤ã³ã¹ãã¼ã«ãã¾ãï¼å°ãæéããããããã§ãï¼ã
$ rustup target add wasm32-wasip2
ä»ã®Rustã¨ã³ã·ã¹ãã ã§ã¯ãä»ã«ç¹å¥ãªã³ãã³ãã©ã¤ã³ãã¼ã«ã¯ä¸è¦ã§ãã
ãã¦ãããã¸ã§ã¯ããä½ãã¾ãã
$ cargo new --lib componentize_mrbe
Cargo.toml ãç·¨éãã¾ãã
ã¾ã wit-bindgen ã¯å¿
è¦ãªã®ã§ã追å ãã¾ããmrubyedgeï¼RCçï¼ã追å ã crate-type = ["cdylib"]
ã«ããå¿
è¦ãããã¾ãã [profile.release]
ã¯ç´æ¥åä½ã«é¢ä¿ãªãã¨æãã¾ããé©å®åãã¦ããã¾ãã
ããããæãã
[package] name = "componentize_mrbe" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [profile.release] codegen-units = 1 opt-level = "s" debug = false strip = false lto = true [dependencies] mrubyedge = "1.0.0-rc2" wit-bindgen = "0.36.0"
ã¾ããç¾ç¶ mruby/edge ã§wasmãä½ãã«ã¯ mrbc ã³ãã³ãã§ä½ã£ãmrubyãã¤ããªãå¥éå¿ è¦ãªã®ã§ããã®è¾ºãçºããªãã3.3.0ãã¤ã³ã¹ãã¼ã«ãã¦ãã ãã*1ã
mrbcãç¨æããã以ä¸ã®ãããªRubyã¹ã¯ãªããã run.mrb
ã«ãã¾ããputsãfibããã豪è¯çã«ãã¾ããã
def run puts "Hello, World from Really Ruby Script!" puts "fib(20) = #{fib(20)}" 0 end def fib(n) n < 2 ? n : fib(n - 1) + fib(n - 2) end
$ mrbc -o src/run.mrb src/mrblib/run.rb
mrbãã¡ã¤ã«ãç¨æã§ãããwitãã¡ã¤ã«ãç¨æãã¾ããããããã¸ã§ã¯ãã® wit/root.wit
ã¨ãããã¡ã¤ã«ã以ä¸ã®ããã«ãã¾ãã
package root:component; world root { export wasi:cli/run@0.2.0; } package wasi:cli@0.2.0 { interface run { run: func() -> result; } }
ãããWASIã®å®ç¾©ã®witãã¡ã¤ã«ãè½ã¨ããã°ãã¿ãããªæé ãè¼ã£ã¦ãã¾ãããä»å㯠wasip2 ã使ãã®ã§ç´æ¥witã«æ¸ããªãã¦è¯ãããã§ãcargoã§ä¸æããã¨ãã£ã¦ãããã¿ããã§ãã wasi:[email protected]
ã¯ç´æ¥exportãã¦ããã®ã§ç´æ¥è¨è¿°ãã¾ãã
ããã§ãããããRustãæ¸ãã¾ããã³ã¼ã src/lib.rs
ã¯ãããªæãã§æ¸ãã¾ãã
extern crate mrubyedge; wit_bindgen::generate!({ world: "root", generate_all }); use exports::wasi::cli::run::Guest; use mrubyedge::yamrb::helpers::mrb_funcall; struct TheRoot; const CODE: &[u8] = include_bytes!("mrblib/run.mrb"); impl Guest for TheRoot { fn run() -> Result<(),()> { let mut rite = mrubyedge::rite::load(CODE).unwrap(); let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite); let args = vec![]; vm.run().unwrap(); let result = mrb_funcall(&mut vm, None, "run", &args).unwrap(); match result.value { mrubyedge::yamrb::value::RValue::Integer(v) => { if v == 0 { Ok(()) } else { Err(()) } }, _ => { Err(()) } } } }
wit_bindgen::generate!
㯠wit
é
ä¸ã®å®ç¾©ãè¦ã¦ã°ã«ã¼ã³ã¼ããçæãã¾ããã©ãããã³ã¼ããçæãããï¼ ã¯å®ã¯ã³ãã³ãã©ã¤ã³ãã¼ã«ã§ã確èªã§ãã¾ãã
$ cargo install wit-bindgen-cli $ wit-bindgen rust --world root --generate-all wit/root.wit Generating "root.rs"
ãã® root.rs
ã include!()
ãã¦ãå¤ååããã§ãããã£ããã¨ã¯ãªããã
ä¸è¨ã®ãã¡ã¤ã«ãè¦ãã°åããéãã Guest
ã¨ãã run() -> Result<(),()>
ãå®è£
ããtraitãçæãããã®ã§ããã® run() ã®å®è£
ãæ¸ãã¦ãããã°ãwitå´ã® run() ã«å¯¾å¿ããé¢æ°ãæ¸ãã¾ããrun()
ã¨ããé¢æ°åã¨ã·ã°ããã£ã¯å½ç¶witã®å®ç¾©ã«ããã¾ãã
ãã®ä¸èº«ã¨ãã¦ã mruby/edge ã®ãã¤ããªãèªã¿è¾¼ãã§é¢æ°ãå®è¡ããã³ã¼ããæ¸ããã®ãä¸è¨ã³ã¼ãã§ãã
ã§ãããã¾ã§ããããã¨ã¯æ®éã«ã³ã³ãã¤ã«ããã°OKã
$ cargo build --target wasm32-wasip2 --release
æ¬å½ã«æ®éã®ãæ¨æºçãªæ¹æ³ã§ã®ãã«ãã§ãã
ãã㧠./target/wasm32-wasip2/release/componentize_mrbe.wasm
ãã§ãã¦ããã wit ãè¦ã¦ã¿ã¾ãããã
$ wasm-tools component wit ./target/wasm32-wasip2/release/componentize_mrbe.wasm package root:component; world root { import wasi:cli/[email protected]; import wasi:cli/[email protected]; import wasi:io/[email protected]; import wasi:io/[email protected]; import wasi:cli/[email protected]; import wasi:cli/[email protected]; import wasi:cli/[email protected]; import wasi:clocks/[email protected]; import wasi:filesystem/[email protected]; import wasi:filesystem/[email protected]; import wasi:random/[email protected]; export wasi:cli/[email protected]; } package wasi:[email protected] { interface error { resource error; } interface streams { use error.{error}; resource output-stream { check-write: func() -> result<u64, stream-error>; write: func(contents: list<u8>) -> result<_, stream-error>; blocking-write-and-flush: func(contents: list<u8>) -> result<_, stream-error>; blocking-flush: func() -> result<_, stream-error>; } variant stream-error { last-operation-failed(error), closed, } resource input-stream; } } package wasi:[email protected] { interface environment { get-environment: func() -> list<tuple<string, string>>; } interface exit { exit: func(status: result); } interface stdin { use wasi:io/[email protected].{input-stream}; get-stdin: func() -> input-stream; } interface stdout { use wasi:io/[email protected].{output-stream}; get-stdout: func() -> output-stream; } interface stderr { use wasi:io/[email protected].{output-stream}; get-stderr: func() -> output-stream; } interface run { run: func() -> result; } } ...
wasi p2é¢ä¿ã®ã¤ã³ã¿ãã§ã¼ã¹ã§ä½¿ã£ã¦ãããã®ã¯Rustãå ¨é¨ç¨æãã¦ããã¾ãããä¸ã®ä¸ã¯é²æ©ãã*2ã
ããã¦ãã®ãã¤ããªã¯ãã®ã¾ã¾ wasmtime ã§åããã¾ããæä½ãWASMã¨éã£ã¦æ¨æºåºåã«æ¸ãåºããã
$ wasmtime ./target/wasm32-wasip2/release/componentize_mrbe.wasm Hello, World from Really Ruby Script! fib(20) = 6765
ã¨ãããã¨ã§ããã¨ã¯èãã®ã³ã¼ãçæï¼ã¨è¨ã£ã¦ãè¤éã§ã¯ããã ããï¼ã¨ãä»æ§ã決ããã° mruby/edge ã§Component対å¿WASMãã¤ããªãä½ããããã«ãªããããã¨è¦éããã¨ããã§ä»æ¥ã¯ããã¾ãã
VMãæ¸ãç´ãã¦ä»¥æ¥ãè¨è¨ãè¦éããããã«ãªã£ãæãããã®ã§ãã¨ããããTCPã¯ã©ã¹ã§ãå®è£ ãã¦ã¦ã§ããµã¼ãã§ãç«ã¡ä¸ãããããª...ããã¨ãRustãæ¸ãããRubyistã®ã³ã³ããªãã¥ã¼ãã¯æè¿ãã¦ã¾ãã¨ããæãã
*1:è¿ããã¡ã«mrbcã³ãã³ãã®Cã³ã¼ããRustã§èãã©ãããããããªcrateã§ãé ããããª...ã¨ããæ°æã¡
*2:ãªãrandomã¨ãclockã¨ããç¡é§ã«importãã¦ãã¾ãããããã¯ä»¥åå®è£ ãã¦ããrandã¨ãã®ä¾åããã®ã¾ã¾ã«ãã¦ããã ãã¨ãã横çã§ãã...ããã®ãã¡RandomãTimeã¯ã©ã¹ãåå®è£ ãã¾ãã