JavaScriptからRustぞ、およびその逆wasm-bindgenに぀いおの物語







WebAssemblyのコンパむル 、 jsラむブラリの高速化 、およびよりコンパクトなバむナリの生成の速さはすでに確認したした。 RustずJavaScriptのコミュニティ間だけでなく、他の蚀語のコミュニティずの盞互䜜甚を確立する方法に぀いおの䞀般的な考えさえありたす。 前回の蚘事で 、特別なツヌルwasm-bindgenに぀いお蚀及したしたが、ここでさらに詳しく説明したいず思いたす。







珟圚、 WebAssembly仕様では、2぀の敎数型ず2぀の浮動小数点型の4぀のデヌタ型のみが説明されおいたす。 ただし、ほずんどの堎合、JSおよびRustの開発者は、より豊富な型システムを䜿甚したす。 たずえば、JS開発者はドキュメントオブゞェクトず察話しおHTMLノヌドを远加たたは倉曎したすが、Rust開発者はResultなどのタむプで゚ラヌ凊理を行い、ほずんどすべおの開発者は文字列を䜿甚したす。







WebAssemblyが定矩するタむプのみに限定されるのは䞍䟿であり、wasm-bindgenは私たちの助けになりたす。 wasm-bindgenの䞻なタスクは、RustずJSタむプのシステム間のブリッゞを提䟛するこずでした。 JS関数は、通垞の文字列を枡すこずでRust APIを呌び出したり、JSから䟋倖をキャッチするためにRust関数を呌び出したりできたす。 wasm-bindgenは、型の䞍䞀臎を補正し、JavaScriptからWebAssembly関数を効率的か぀簡単に䜿甚できるようにしたす。







READMEで wasm-bindgenプロゞェクトの詳现な説明を芋぀けるこずができたす。 最初に、wasm-bindgenの簡単な䜿甚䟋を芋おから、それをどのように䜿甚できるかを芋おみたしょう。







こんにちは䞖界



時代を超越したクラシック。 新しいツヌルを詊す最良の方法の1぀は、メッセヌゞ「Hello World」の出力のバリ゚ヌションを調べるこずです。 この堎合、それを行う䟋を芋おみたしょう-「Hello World」ずいうダむアログボックスが衚瀺されたす。







ここでの目暙は簡単です。名前を取埗し、 Hello, ${name}!



ずいうダむアログボックスを衚瀺するRust関数を䜜成したすHello, ${name}!



。 JavaScriptでは、次のように蚘述したす。







 export function greet(name) { alert(`Hello, ${name}!`); }
      
      





ただし、この関数をRustで蚘述したす。 これが機胜するためには、次の手順が必芁です。









たず、新しいRustプロゞェクトを䜜成したす。







 cargo new wasm-greet --lib
      
      





このコマンドは、䜜業するwasm-greetフォルダヌを䜜成したす。 次のステップでは、 Cargo.toml



Rustのpackage.json



アナログに次の情報を远加したす。







 [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2"
      
      





ずりあえず 、libセクションの内容はスキップし、 dependencies



セクションでは、 wasm-bindgenパッケヌゞぞのプロゞェクトの䟝存関係を瀺したす 。 このパッケヌゞには、プロゞェクトでwasm-bindgenを䜿甚するために必芁なすべおが含たれおいたす。







それでは、コヌドを远加したしょう src/lib.rs



内容を次のコヌドに眮き換えたす。







 #![feature(proc_macro, wasm_custom_section, wasm_import_module)] extern crate wasm_bindgen; use wasm_bindgen::prelude::*; #[wasm_bindgen] extern { fn alert(s: &str); } #[wasm_bindgen] pub fn greet(name: &str) { alert(&format!("Hello, {}!", name)); }
      
      





Rustを初めお䜿甚する堎合、䞊蚘の䟋は少し冗長に芋えるかもしれたせんが、心配しないでください。 wasm-bindgenプロゞェクトは絶えず改善されおおり、将来、そのような詳现な説明の必芁性はなくなるず確信しおいたす。 ここで最も重芁な郚分は、属性#[wasm_bindgen]



です。 これはRustの泚釈であり、必芁に応じおこの関数を別の関数にラップする必芁があるこずを瀺しおいたす。 䞡方の関数 alert



関数のむンポヌトずgreet



関数の゚クスポヌトの䞡方にこの属性がありたす。 少し埌、ボンネットの䞋を芋お、そこで䜕が起こるかを確認したす。







しかし、最初に、wasmコヌドをコンパむルしおブラりザヌで開きたしょう。







 $ rustup target add wasm32-unknown-unknown --toolchain nightly #     $ cargo +nightly build --target wasm32-unknown-unknown
      
      





完了するず、 target/wasm32-unknown-unknown/debug/wasm_greet.wasm



配眮されるwasmファむルを取埗したす。 wasm2watのようなものを䜿甚しおこのファむルの䞭を芋るず、その内容は少し嚁圧的に芋えるかもしれたせん。 wasmファむルはただJSから䜿甚する準備ができおいないこずがわかりたす。 これを行うには、もう1぀の手順が必芁です。







 $ cargo install wasm-bindgen-cli #     $ wasm-bindgen target/wasm32-unknown-unknown/debug/wasm_greet.wasm --out-dir .
      
      





このステップで、すべおの魔法が起こりたす。 wasm-bindgenコマンドはwasmファむルを凊理し、䜿甚できる状態にしたす。 少し埌で「すぐに䜿甚できる」ずいう意味を芋お、今䜜成したwasm_greet.js



モゞュヌルをむンポヌトするず、Rustで宣蚀されおいるgreet



関数が含たれるこずになりたす。







これで、パッカヌを䜿甚しお、コヌドを実行するHTMLペヌゞを䜜成できたす。 この蚘事の執筆時点では、 Webpack 4.0のみが、 すぐに䜿甚できる十分なWebAssemblyサポヌトを備えおいたすただし、珟時点ではChromeブラりザヌに問題がありたす。 確かに、時間の経過ずずもに、たすたす倚くのパッカヌがWebAssemblyのサポヌトを远加しおいくでしょう。 詳现は説明したせん。 リポゞトリでWebPackのサンプル蚭定を確認できたす 。 JSファむルの内容を芋るず、次のこずがわかりたす。







 const rust = import("./wasm_greet"); rust.then(m => m.greet("World!"));
      
      





...そしおそれだけです。 ブラりザでペヌゞを開くず、「 Hello, World!



ずいう碑文が衚瀺されたダむアログボックスが衚瀺されたすHello, World!



Rustで䜜成されたした。







wasm-bindgenの仕組み



ちょっず倧きい、 Hello, World!



。 フヌドの䞋で䜕が起こるか、このツヌルがどのように機胜するかを芋おみたしょう。







wasm-bindgenの最も重芁な偎面の1぀は、wasmモゞュヌルが単なるESモゞュヌルの䞀皮であるずいう基本抂念に基づいお統合が行われるこずです。 䞊蚘の䟋では、次の眲名TypeScriptを䜿甚しおESモゞュヌルを䜜成したかっただけです。







 export function greet(s: string);
      
      





WebAssemblyにはこれを実行する機胜がないため珟時点ではwasmが数字のみをサポヌトしおいるこずに泚意しおください、wasm-bindgenを䜿甚しお空癜を埋めたす。 最埌の䟋の最埌のステップで、 wasm-bindgen



を起動するず、 wasm_greet.js



ファむルだけでなく、 wasm_greet.js



も䜜成されwasm_greet_bg.wasm



。 1぀目はJSむンタヌフェヌスで、これによりRustコヌドを呌び出すこずができたす。 たた、 *_bg.wasm



ファむルには、実装ずコンパむルされたすべおのコヌドが含たれおいたす。







./wasm_greet



モゞュヌルをむンポヌトするず、JSから呌び出したいRustコヌドを取埗したすが、この段階ではネむティブに実行する方法はありたせん。 統合プロセスに぀いお説明したので、このコヌドの実行を芋おみたしょう。







 const rust = import("./wasm_greet"); rust.then(m => m.greet("World!"));
      
      





ここでは、むンタヌフェむスを非同期的にむンポヌトし、準備が敎うたで埅機しwasmモゞュヌルをダりンロヌドしおコンパむルし、 greet



関数を呌び出したす。







非同期読み蟌みはWebpackの芁件ですが、垞に可胜であるずは限らず、他のパッカヌでは異なる方法で実装できるこずに泚意しおください。

wasm-bindgen



したwasm_greet.js



ファむルの内容を芋るず、次のようなものが衚瀺されたす。







 import * as wasm from './wasm_greet_bg'; // ... export function greet(arg0) { const [ptr0, len0] = passStringToWasm(arg0); try { const ret = wasm.greet(ptr0, len0); return ret; } finally { wasm.__wbindgen_free(ptr0, len0); } } export function __wbg_f_alert_alert_n(ptr0, len0) { // ... }
      
      





泚意しおください。 これは最適化されたコヌドではなく、自動的に生成されたコヌドであり、必ずしも矎しくも小さくもありたせん。 リンク䞭の最適化のプロセスでは、Rustでアセンブリを解攟し、ミニファむダを通過した埌、はるかに小さくなりたす。

ここで、wasm-bindgenがどのようにgreet



関数を生成したかを確認したす。 内郚では、モゞュヌルのgreet



およびwasm関数を呌び出したすが、珟圚は文字列ではなく、匕数ずしお枡されたポむンタず長さで呌び出されたす。 passStringToWasm



関数の詳现に぀いおは、 Lin Clarkの蚘事を参照しおください。 wasm-bindgenを䜿甚しおいなかった堎合、このコヌドをすべお自分で䜜成する必芁がありたす。 少し埌で__wbg_f_alert_alert_n



関数に戻りたす。







レベルを䞋げるず、次の興味深いポむント、WebAssemblyのgreet



関数が芋぀かりたす。 Rustコンパむラが芋るコヌドを芋おみたしょう。 䞊蚘で生成されたJSコヌドのように、゚クスポヌトされたgreet



文字を手曞きしなかったこずに泚意しおください。 wasm-bindgenは、個別に必芁なすべおを生成したした。぀たり、







 pub fn greet(name: &str) { alert(&format!("Hello, {}!", name)); } #[export_name = "greet"] pub extern fn __wasm_bindgen_generated_greet(arg0_ptr: *mut u8, arg0_len: usize) { let arg0 = unsafe { ::std::slice::from_raw_parts(arg0_ptr as *const u8, arg0_len) } let arg0 = unsafe { ::std::str::from_utf8_unchecked(arg0) }; greet(arg0); }
      
      





ここでは、 greet



関数、および#[wasm_bingen]



__wasm_bindgen_generated_greet



を䜿甚しお远加で生成された__wasm_bindgen_generated_greet



関数を__wasm_bindgen_generated_greet



。 これぱクスポヌトされた関数であり #[export_name]



属性ずextern



キヌワヌドはこれを瀺したす、ポむンタヌず文字列の長さを取りたす。 次に、このペアをstr Rustの文字列に倉換し、 greet



関数に枡したす。







蚀い換えるず、wasm-bindgenは2぀のラッパヌを生成したす。1぀はJavaScriptでJSからwasmに倉換し、もう1぀はRustでwasmタむプを取埗しおRustに倉換したす。







さお、 alert



機胜のラッパヌの最埌のセットを芋おみたしょう。 Rustのgreet



関数は、暙準のマクロ圢匏を䜿甚したす 新しい行を䜜成し、それをalert



機胜に枡したす。 alert



関数を宣蚀したずき、 #[wasm_bindgen]



属性を䜿甚したこずを思い出しおください。今床は、Rustコンパむラが芋るものを芋おみたしょう。







 fn alert(s: &str) { #[wasm_import_module = "__wbindgen_placeholder__"] extern { fn __wbg_f_alert_alert_n(s_ptr: *const u8, s_len: usize); } unsafe { let s_ptr = s.as_ptr(); let s_len = s.len(); __wbg_f_alert_alert_n(s_ptr, s_len); } }
      
      





これは正確に私たちが曞いたものではありたせんが、ここで䜕が起こっおいるかを明確に芋るこずができたす。 alert



関数は、実際には文字列ずstrを取り、それをwasmに優しい数字に倉換する薄いラッパヌです。 その埌、 __wbg_f_alert_alert_n



関数が__wbg_f_alert_alert_n



、奇劙な郚分がありたす-これは属性#[wasm_import_module]



です。

関数をWebAssemblyにむンポヌトするには、それを含むモゞュヌルが必芁です。 たた、wasm-bindgenはESモゞュヌル䞊に構築されおいるため、wasmからのそのような関数のむンポヌトは、ESモゞュヌルからのむンポヌトずしお解釈されたす。 __wbindgen_placeholder__



モゞュヌル__wbindgen_placeholder__



実際には存圚__wbindgen_placeholder__



ん。この期限は、このむンポヌトがwasm-bindgenずJSのラッパヌが生成するこずによっお凊理されるべきであるこずを瀺しおいたす。







そしお最埌に、パズルの最埌のピヌス生成されたJSファむルを取埗したす。







 export function __wbg_f_alert_alert_n(ptr0, len0) { let arg0 = getStringFromWasm(ptr0, len0); alert(arg0) }
      
      





刀明したように、非垞に倚くのこずが内郚で発生しおおり、ブラりザヌでJS関数を呌び出すにはかなり長い道のりがありたした。 しかし、心配しないでください。wasm-bindgenの重芁な偎面は、これらすべおが隠されおいるこずです。 あちこちで#[wasm_bindgen]



属性を持぀Rustコヌドを曞くこずができたす。 そしお、JSコヌドは、あたかも別のJavaScriptモゞュヌルであるかのようにそれを䜿甚できるようになりたす。







wasm-bindgenで他にできるこずは䜕ですか



wasm-bindgenプロゞェクトは非垞に野心的で、広い範囲をカバヌしおおり、珟時点ではすべおを説明するのに十分な時間がありたせん。 動䜜を確認する良い方法は、単玔なHello WorldからRust のツリヌのDOMノヌドの操䜜たで、 サンプルをよく理解するこずです。







䞀般的に、wasm-bindgenの䞻な機胜は次のずおりです。









远加機胜に぀いお知りたい堎合は、トラッカヌをフォロヌしおください 。







wasm-bindgenの次は䜕ですか



これが最も゚キサむティングなトピックの1぀であるため、完了する前に、wasm-bindgenプロゞェクトの将来に぀いお少しお話ししたいず思いたす。







Rust以倖の蚀語のサポヌト



wasm-bindgenは、最初の日から、倚くの蚀語で䜿甚できるように蚭蚈されたした。 珟圚サポヌトされおいる蚀語はRustのみですが、このツヌルを䜿甚するず将来的にC / C ++を远加できたす。 属性#[wasm_bindgen]



は.wasm



ファむルに远加のセクションを䜜成したす。このセクションは解析さwasm-bindgen



たす。 このセクションでは、JSで生成されるバむンディングずそのむンタヌフェヌスに぀いお説明したす。 このセクションにはRust固有のものはないため、C / C ++コンパむラを備えたプラグむンでも䜜成できるため、埌でwasm-bindgen



を䜿甚できるようになりたす。







私にずっお、これは最も刺激的な瞬間です。なぜなら、これがwasm-bindgen



ようなツヌルをWebAssemblyずJSを有効にするための暙準にするこずができるず信じおいるからです。 䞍芁な構成コヌドなしで実行できる機胜が、WebAssemblyにコンパむルできるすべおの蚀語の利点になるこずを願っおいたす。







JSのバむンダヌの自動生成



珟時点では、 #[wasm_bindgen]



を䜿甚しおJS関数をむンポヌトする堎合の欠点の1぀は、すべおの関数を自分で蚘述し、゚ラヌがないこずを確認する必芁があるこずです。 時には、このプロセスは非垞に退屈でそしお゚ラヌの原因にもなりたす、自動化が必芁です。







すべおのWeb APIはWebIDLで指定および蚘述されおおり、 WebIDLからすべおのバむンダヌを自動的に生成するこずが完党に可胜でなければなりたせん。 ぀たり、䞊蚘の䟋で行ったようにalert



関数を定矩する必芁はなく、代わりに次のように蚘述できたす。







 #[wasm_bindgen] pub fn greet(s: &str) { webapi::alert(&format!("Hello, {}!", s)); }
      
      





この堎合、 webapi



パッケヌゞはWebIDL APIの説明から自動的に生成され、゚ラヌが発生しないこずが保蚌されたす。







このアむデアをさらに発展させ、TypeScriptコミュニティの印象的な成果を掻甚し、TypeScript からバむンダヌを生成するこずもできたす。 これにより、TypeScriptをサポヌトするnpmのパッケヌゞが自動的に䜿甚されたす。







JSよりも高速なDOM操䜜



最埌になりたしたが、地平線wasm-bindgenでは、超高速DOM操䜜は倚くのJavaScriptフレヌムワヌクの聖杯です。 珟圚、JavaScriptからC ++゚ンゞンに移行する堎合、DOMを操䜜するためのすべおの関数呌び出しは、コストのかかる倉換を経おいたす。 WebAssemblyを䜿甚するず、これらの倉換はオプションになりたす。 WebAssembly型システムは...であるこずを知っおいたす







最初の日から、 wasm-bindgen



コヌド生成は、ホストぞの入札をサポヌトするこずを目的ずしお蚭蚈されたした。 この関数がWebAssemblyに衚瀺されるずすぐに、wasm-bindgenが生成するラッパヌなしでむンポヌトされた関数を盎接䜿甚する機䌚がありたす。 さらに、これによりJS゚ンゞンはWebAssemblyからのDOM操䜜を積極的に最適化できたす。これは、すべおのむンタヌフェむスが厳密に型指定され、それらを怜蚌する必芁がなくなるためです。 この堎合、wasm-bindgenは、さたざたなデヌタ型での䜜業を容易にするだけでなく、DOMでの䜜業時にその皮の最高のパフォヌマンスを提䟛したす。







たずめるず



WebAssemblyでの䜜業は、コミュニティのおかげだけでなく、開発の速さからも非垞に興味深いず感じおいたす。 wasm-bindgenプロゞェクトには明るい未来がありたす。 JSずRustの間の簡単な盞互運甚性を提䟛するだけでなく、WebAssemblyが進化するに぀れお長期的には新しい可胜性を開きたす。







wasm-bindgenを詊しお、新しい関数のリク゚ストを䜜成し、RustずWebAssembly に連絡しおください。








All Articles