{"id":23516567,"url":"https://github.com/ambientrun/wasm-interop","last_synced_at":"2025-05-13T23:12:46.924Z","repository":{"id":183902051,"uuid":"657227883","full_name":"AmbientRun/wasm-interop","owner":"AmbientRun","description":"Demonstrating webassembly running and interoperating with other web assembly modules.","archived":false,"fork":false,"pushed_at":"2023-07-26T08:19:11.000Z","size":31,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-16T22:35:17.119Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AmbientRun.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-06-22T15:38:36.000Z","updated_at":"2024-01-08T12:16:06.000Z","dependencies_parsed_at":"2023-07-26T09:47:04.990Z","dependency_job_id":null,"html_url":"https://github.com/AmbientRun/wasm-interop","commit_stats":null,"previous_names":["ambientrun/wasm-interop"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmbientRun%2Fwasm-interop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmbientRun%2Fwasm-interop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmbientRun%2Fwasm-interop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmbientRun%2Fwasm-interop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AmbientRun","download_url":"https://codeload.github.com/AmbientRun/wasm-interop/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254042418,"owners_count":22004901,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-25T15:14:07.967Z","updated_at":"2025-05-13T23:12:41.912Z","avatar_url":"https://github.com/AmbientRun.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebAssembly Interop\n\nThis example project demonstrates WebAssembly interop.\n\n- loading and executing a wasm module from javascript, henceforth called `bootstrapping`\n\n- Loading wasm from wasm and calling it\n\n## Wasm to Wasm\n\nWhen compiling a Rust library to WebAssembly, it is built like a `C` library.\n\nThe exported function can only take and return simple primitive types.\n\n`String`, `structs`, `\u0026` etc are not allowed.\n\n`struct`s are rust-specific, and there is no concept of passing composite types to wasm. It is possible to pass some\ncomposite types across the boundaries, as rust will `flatten` the struct fields into separate arguments, but on the\nwire between wasm it is plain arguments. The struct support is only some sugar and convenience that the rust\ncompiler will provide. To make this work, `#[repr(C)]`is required to ensure `rustc` is not reordering fields and\nadding padding.\n\n`Strings` are similar, and have a pointer inside them to the Wasm modules memory. Passing it to JavaScript or\nbetween modules require disassembly, and re-encoding and allocating on the receiver side.\n\nPassing pointers \"raw\" between modules is dangerous since pointers have no memory identifier, and will always refer\nto a byte offset in the current module. As such, passing a pointer from `A =\u003e B` which points to valid memory in `A`\nwill point to something completely different in the memory of `B`. As such, serialization is done.\n\n`\u0026` are not allowed since rusts lifetimes don't map over FFI. Fat slices are not allowed either.\n\n# Wasm-bindgen\n\nSo, you may be wondering.\n\nHow does `wasm-bindgen` allow calling into Rust, and calling from Rust into Js using complicated types such as\n`String`s, `struct`s, `\u0026` etc?\n\nThe `#[wasm_bindgen]` proc macro generates the glue required that wraps your nice function with an _FFI-safe_\nfunction that takes raw offsets and primitive types, and then assembles them together into rust types to call your nice Rust function.\n\nFor example\n\n```rust\nfn foo(name: String)\n```\n\nGets converted into\nThe glue is generated to convert a raw byte address and a length into a rust UTF-8 string.\n\n```rust\n\nunsafe fn foo(name_ptr: *const u8, name_len: i32) {\n    let name = slice::from_raw_parts(name_ptr, name_len);\n    let name = String::from_utf8_unchecked(name);\n\n    foo(name)\n}\n```\n\nThe function is then exported using the `C` abi as:\n\n`fun(i32, i32)`\n\nNotably, pointers are passed as integer values, I.e; 32-bit signed integers.\n\nCalling this function requires allocating and copying your UTF-8 string data into the target modules memory, and then\nusing that pointer to call the function.\n\n**The passed pointer must be from the memory of the module that is called**\n\nJust passing your `str::as_ptr()`, or `char*` from your module to the target will result in undefined behavior as that pointer\nnow refers to something else. You need to copy it into the target memory before calling. A good way to think of it is as\ncalling between different system processes, which have a different address space.\n\nCalling this function from _JavaScript_, requires taking your js `string` and encoding it into an `Uint8Array` and then\nallocating and copying the bytes into the target module's memory to obtain a pointer. The pointer is then what is\nultimately passed into wasm.\n\n## Wasm bindgen CLI\n\nThe `wasm-bindgen` cli will consume and parse the generated Rust binary `.wasm` file.\n\nDuring macro time in rust, extra functions called `__wbindgen_describe_{func}` will be emitted, and these will end up\nas exported functions in the wasm binary.\n\nThe `wasm-bindgen` tool will find and execute these functions to obtain reflection data to reconstruct the higher-order\ntypes that the function will consume, such as (i32, i32) to a `String`. Knowing this, the appropriate `js`\nfunctions will be generated which takes the corresponding type, and boils it down into primitive types, allocating and\ncopying to the target memory if needed. This ensures that the consuming `JavaScript` code can call a wasm function\nthrough the `mywasm.js` file using conventional types and javascript objects rather than integers.\n\n## Links\n\n- (Rust Type conversions)[https://rustwasm.github.io/docs/book/print.html]\n- (WASI Marshalling)[https://rob-blackbourn.github.io/blog/webassembly/wasm/javascript/c/clang/wasi-sdk/marshalling/2020/07/02/wasi-marshalling.html]\n- (FromWasmAbi)[https://docs.rs/wasm-bindgen/latest/wasm_bindgen/convert/trait.FromWasmAbi.html]\n- (Exporting to Rust)[https://rustwasm.github.io/wasm-bindgen/contributing/design/exporting-rust.html]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fambientrun%2Fwasm-interop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fambientrun%2Fwasm-interop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fambientrun%2Fwasm-interop/lists"}