ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

wasm-bindgen 中 char 类型的跨语言传递:以 examples/char 为例从用法到 ABI 实现

wasm-bindgen 中 char 类型的跨语言传递:以 examples/char 为例从用法到 ABI 实现 开发工具【免费下载链接】wasm-bindgenFacilitating high-level interactions between Wasm modules and JavaScript项目地址https://gitcode.com/gh_mirrors/wa/wasm-bindgen点击查看免费下载本文以 wasm-bindgen 仓库自带的examples/char示例为线索系统讲解 Rustchar类型如何与 JavaScript 字符串互相传递从可直接运行的示例工程、Counter类的实战用法到源码层基于u32的 ABI 编码、以及针对 Unicode 标量值边界包括代理项与非法输入的完整测试验证。读完本文你将掌握在 wasm-bindgen 项目中安全、高效地跨边界传递单字符数据并理解其底层机制。示例概览一个关于字符的计数器应用examples/char是 wasm-bindgen 官方示例之一主题是与char类型打交道Working with thechartype。它构建了一个网页应用每点击一次按钮就从一份包含数百个 Unicode 字符的列表中随机取出一个字符作为Counter的键key并展示当前计数点击按钮即可对计数加一。与仓库中其他示例一样该工程同时包含 Rust 与 JavaScript 两侧代码覆盖了完整的构建 → 加载 → 交互链路文件作用examples/char/src/lib.rsRust 侧定义Counter结构体与字符相关的公开 APIexamples/char/index.jsJS 侧生成随机字符、调用 Rust 方法、渲染 DOMexamples/char/index.html页面骨架与样式examples/char/chars-list.js预置的 Unicode 字符池含 ASCII、拉丁扩展、希腊文、西里尔文、emoji 等examples/char/Cargo.tomlRust 工程配置cdylibexamples/char/package.jsonnpm 脚本与 devDependenciesexamples/char/webpack.config.jswebpack wasm-pack 插件配置注意示例对应仓库内的根 README 位于 examples/char/README.md其中说明示例编译后的在线演示与文档托管在 wasm-bindgen 项目站点的exbuild/char/与examples/char.html页面。本地运行方式原文档给出的运行方式非常简洁只需两步$ npm run serveserve脚本定义在 examples/char/package.json 中等价于webpack serve会同时启动 webpack dev server 与 wasm-pack 编译流程。随后在浏览器中访问http://localhost:8080即可看到示例页面一个add counter按钮点击后页面中会出现一个以随机字符命名的计数器卡片。如果想要一次性产出静态构建产物也可以使用同文件中的另一个脚本$ npm run build它执行webpack把结果输出到dist/char/目录见下方构建配置小节。Rust 侧用 char 作为结构体字段与参数示例的 Rust 代码非常集中地展示了char在 wasm-bindgen 中的三种典型用法结构体字段、构造函数参数、getter 与 setter 方法。核心实现在 examples/char/src/lib.rsuse wasm_bindgen::prelude::*; // lifted from the console_log example #[wasm_bindgen] extern C { #[wasm_bindgen(js_namespace console)] fn log(s: str); } #[wasm_bindgen] #[derive(Debug)] pub struct Counter { key: char, count: i32, } #[wasm_bindgen] impl Counter { pub fn new(key: char, count: i32) - Counter { log(format!(Counter::new({key}, {count}))); Counter { key, count } } pub fn key(self) - char { log(Counter.key()); self.key } pub fn count(self) - i32 { log(Counter.count); self.count } pub fn increment(mut self) { log(Counter.increment); self.count 1; } pub fn update_key(mut self, key: char) { self.key key; } }从这份代码可以归纳出char在 wasm-bindgen 中的使用要点公开字段Counter.key是char类型在 JS 侧读取key()时返回的是长度为 1 的 JS 字符串单码点字符串参数与返回值new(key: char, ...)、update_key(mut self, key: char)、key(self) - char展示了char作为入参、出参、可写状态的全流程与i32等原生类型混用Counter::new同时接收char与i32说明char在 ABI 层面与数字类型一样走按值传递路径详见下文 ABI 小节日志辅助示例从console_log示例中借来了#[wasm_bindgen(js_namespace console)] fn log(s: str)方便在浏览器控制台观察方法调用过程。JS 侧随机字符池与 DOM 交互JS 侧的工作分两部分维护字符池、调用 Rust 生成计数器。字符池覆盖广泛 Unicode 范围的测试素材examples/char/chars-list.js 导出chars数组内容从 ASCII 可打印字符!、#、$…一直延伸到拉丁扩展、希腊字母、西里尔字母以及大量 emoji如、。这一设计并非巧合——字符池越宽越能覆盖char跨边界传递时可能遇到的各种码位区间包括1 字节码位ASCII如A、z2 字节码位如¡、Ä3 字节码位如Ā、ϑ4 字节码位emoji如。调用 Rust 并渲染examples/char/index.js 的核心逻辑如下import { chars } from ./chars-list.js; let imp import(./pkg); let mod; let counters []; imp.then(wasm { mod wasm; addCounter(); document.getElementById(add-counter).addEventListener(click, () addCounter()); }).catch(console.error); function addCounter() { let ctr mod.Counter.new(randomChar(), 0); counters.push(ctr); update(); } function randomChar() { let idx Math.floor(Math.random() * (chars.length - 1)); return chars.splice(idx, 1)[0]; // 取出后从池中移除避免重复 }关键点异步加载import(./pkg)动态导入 wasm-pack 生成的模块pkg目录由WasmPackPlugin自动产出构造 Rust 对象mod.Counter.new(randomChar(), 0)直接以 JS 字符串调用 Rust 构造函数说明 JS 侧不需要任何显式转换——一个字符的 JS 字符串就是 Rustchar的天然表示读取字符counter.key()返回的字符串被用于newCounter(key, value, cb)中的document.createTextNode(Counter key)直接拼入 DOM 标题更新计数按钮回调调用counter.increment()后刷新列表对应 Rust 侧mut self方法。update()中还有一个值得注意的细节渲染前会保留#add-counter按钮并移除其余子节点实现整块重绘每个计数卡片由newCounter创建其中newField用两个span分别展示字段名与字段值。底层原理char 在 wasm-bindgen 中的 ABI 编码char之所以能在 JS 字符串与 Rust 标量之间无缝切换是因为 wasm-bindgen 为它定义了明确的 ABI 表示。查看 src/convert/impls.rs 的源码impl IntoWasmAbi for char { type Abi u32; #[inline] fn into_abi(self) - u32 { self as u32 } } impl FromWasmAbi for char { type Abi u32; #[inline] unsafe fn from_abi(js: u32) - char { // SAFETY: Checked in bindings. char::from_u32_unchecked(js) } }从源码结构可以提炼出以下事实char的 ABI 类型是u32Rust 侧传入时把char直接按码位Unicode Scalar Value强转为u32返回时由char::from_u32_unchecked还原。整个跨边界过程是单个 32 位整数不涉及内存拷贝或指针。校验发生在绑定层from_abi的 SAFETY 注释明确写着在 bindings 中检查。也就是说wasm-bindgen 生成的胶水代码负责把 JS 侧的单字符字符串先转换成合法的u32码位再交给from_abi。非法输入例如孤立的 UTF-16 代理项、非字符串类型会在这一层被拦截并抛出可读的错误信息见下文测试。与i32等原生类型同路径char同bool、数字一样实现了IntoWasmAbi/FromWasmAbi的按值传递协议这正是它能够作为结构体字段、构造参数自由进出的基础。顺带一提bool的 ABI 也是u32见 src/convert/impls.rs说明用一个 32 位整数承载小型标量是 wasm-bindgen 的通用设计。边界行为测试用例如何验证 char 往返仓库的正式测试位于 tests/wasm/char.rsRust 侧与 tests/wasm/char.jsJS 侧它们把char的行为边界钉得清清楚楚。往返正确性tests/wasm/char.js 覆盖了多种码位宽度的字符assert.strictEqual(wasm.letter(), a); assert.strictEqual(wasm.face(), ); assert.strictEqual(wasm.rust_identity(), \u0000); // U0000 也能传递 assert.strictEqual(wasm.rust_identity(Ղ), Ղ); assert.strictEqual(wasm.rust_identity(ҝ), ҝ); assert.strictEqual(wasm.rust_identity(Δ), Δ); assert.strictEqual(wasm.rust_identity(䉨), 䉨); assert.strictEqual(wasm.rust_js_identity(㊻), ㊻); wasm.rust_letter(a); wasm.rust_face();而 Rust 侧的 tests/wasm/char.rs 提供了对应的rust_identity、rust_js_identity、letter、face、rust_letter、rust_face其中letter() - char返回aface() - char返回4 字节 emoji验证了 Rust → JS 方向rust_identity(c: char) - char原样返回验证 JS → Rust → JS 的完整往返rust_js_identity(c: char) - char先调用 JS 侧js_identity再返回验证 Rust → JS → Rust 的反向链路。可选值语义tests/wasm/char.js 还验证了Optioncharassert.strictEqual(wasm.rust_option_identity(undefined), undefined); assert.strictEqual(wasm.rust_option_identity(null), undefined); assert.strictEqual(wasm.rust_option_identity(), \u0000); assert.strictEqual(wasm.rust_option_identity(\u0000), \u0000);这说明undefined/null会映射为None而空字符串与\u0000都会正确映射为Some(\u0000)并原样返回——JS 空串在这里被当作含有一个 U0000 的字符串处理。非法输入的错误信息tests/wasm/char.js 专门断言了两类非法输入assert.throws(() wasm.rust_identity(55357), /c.codePointAt is not a function/); assert.throws(() wasm.rust_identity(\uD83D), /expected a valid Unicode scalar value, found 55357/); assert.throws(() wasm.rust_option_identity(\uD83D), /expected a valid Unicode scalar value, found 55357/);传入数字如55357时绑定代码尝试调用字符串方法codePointAt失败抛出c.codePointAt is not a function传入孤立的 UTF-16 代理项\uD83D是的高代理位时因为其码位55357落在代理区D800–DFFF不是合法的 Unicode 标量值绑定层抛出expected a valid Unicode scalar value, found 55357。这两条断言直观印证了上文校验在 bindings 层的实现事实wasm-bindgen 不会把非法码位静默塞进 Rust 侧而是显式报错保证char::from_u32_unchecked的 SAFETY 前提始终成立。工程配置让示例跑起来的三个配置文件Rust 侧cdylibexamples/char/Cargo.toml 的配置非常标准[package] authors [The wasm-bindgen Developers] edition 2021 name char publish false version 0.0.0 [lib] crate-type [cdylib] [dependencies] wasm-bindgen { path ../../ }要点crate-type [cdylib]是 wasm-bindgen 工程的标准要求保证编译产物是可供 JS 加载的 wasm 动态库wasm-bindgen { path ../../ }通过相对路径引用仓库根目录的 wasm-bindgen 本体即 Cargo.tomlpublish false表明这是仓库内部的演示 crate。npm 侧webpack wasm-pack 插件examples/char/package.json 只定义了两个脚本{ scripts: { build: webpack, serve: webpack serve }, devDependencies: { wasm-tool/wasm-pack-plugin: catalog:, html-webpack-plugin: catalog:, webpack: catalog:, webpack-cli: catalog:, webpack-dev-server: catalog: } }catalog:表示依赖版本由仓库工作区的 pnpm catalog 统一管理避免各示例版本漂移。构建管道WasmPackPluginexamples/char/webpack.config.js 是整套构建的核心const path require(path); const HtmlWebpackPlugin require(html-webpack-plugin); const webpack require(webpack); const WasmPackPlugin require(wasm-tool/wasm-pack-plugin); module.exports { entry: ./index.js, output: { path: path.resolve(__dirname, .., dist, char), filename: index.js, }, plugins: [ new HtmlWebpackPlugin({ template: index.html }), new WasmPackPlugin({ crateDirectory: __dirname }), ], mode: development, experiments: { asyncWebAssembly: true } };WasmPackPlugin以crateDirectory: __dirname即examples/char为 Rust crate 根目录在 webpack 构建时自动执行 wasm-pack 编译并生成./pkg因此index.js里import(./pkg)才能工作experiments.asyncWebAssembly: true开启 Webpack 5 的异步 wasm 支持与import(./pkg)的异步加载方式匹配HtmlWebpackPlugin以index.html为模板注入打包产物输出统一放到仓库级dist/char/目录与仓库中多个示例共用dist/的结构一致。小结examples/char虽小却是理解 wasm-bindgen 字符传递机制的理想标本用法层面char可作为公开结构体字段、构造参数、getter/setter 返回值JS 侧以单码点字符串直接互操作无需手动编解码ABI 层面char以u32码位形式跨边界传递src/convert/impls.rsRust 侧用char as u32与char::from_u32_unchecked完成双向转换安全层面绑定层负责校验输入非法码位孤立代理项、非字符串会被显式拒绝并抛出错误测试用例tests/wasm/char.rs、tests/wasm/char.js为这一保证提供了完整证据工程层面cdylibWasmPackPluginasyncWebAssembly的组合是仓库所有示例通用的编译即运行模板。如果你需要在 Rust wasm 模块中传递单个 Unicode 字符例如键盘按键、游戏输入、符号标识直接照抄本示例的Counter写法即可Rust 侧用charJS 侧用单字符字符串剩下的交给 wasm-bindgen。赞分享开发工具【免费下载链接】wasm-bindgenFacilitating high-level interactions between Wasm modules and JavaScript项目地址https://gitcode.com/gh_mirrors/wa/wasm-bindgen点击查看免费下载相关推荐PaddleSpeech 位置编码模块深度解析sinusoid_position_encoding 与 scaled_position_encodingPaddleSpeech 位置编码模块深度解析sinusoid_position_encoding 与 scaled_position_encoding 本文开发工具drizzle-orm 0.19.1 新增 PostgreSQL char 数据类型从列定义用法到源码实现drizzle orm 0.19.1 新增 PostgreSQL char 数据类型从列定义用法到源码实现 本篇技术指南围绕 drizzle orm 0.19桌面应用系统编程零代码Modbus TCP调试工具让工业设备通信验证效率提升80%零代码Modbus TCP调试工具让工业设备通信验证效率提升80% 在工业自动化与物联网领域Modbus TCP协议作为设备通信的通用标准其调试过程常因缺深度学习机器学习开发工具上一篇TursoLimbo代码质量指南生产级 SQL 数据库的 Rust 正确性工程实践下一篇LayerDivider免费图片转PSD分层开源工具一张插画自动拆成可编辑图层创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表