欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > rust 编译wasm 使用

rust 编译wasm 使用

2024/10/24 10:21:19 来源:https://blog.csdn.net/qq_36517296/article/details/140583625  浏览:    关键词:rust 编译wasm 使用

创建rust lib 项目

cargo new --lib rust_wasm

修改Cargo.toml

cdylib 是动态库, 可以编译多个跨平台动态库(rlib 是给rust 代码内部用的,例如你写了个算法但是不想暴露算法具体规则只想给别人用,就可以使用rlib 了)

[lib]
crate-type = ["cdylib"]

依赖库

cargo add wasm-bindge

lib.rs rust 代码

例如 暴露方法就使用 #[wasm_bindgen],具体用法看官网文档

use byteorder::{BigEndian, ByteOrder};
use serde::{Deserialize, Serialize};
use serde_json::{self, Value};
use std::io::{Cursor, Read};
use wasm_bindgen::prelude::*;
use serde_wasm_bindgen::{to_value, from_value};
use js_sys::Uint8Array;
use web_sys; // 引入 console 模块#[wasm_bindgen]
pub fn fib(n: u32) -> u32 {if n <= 1 {n} else {fib(n - 1) + fib(n - 2)}
}#[derive(Serialize, Deserialize, Debug)]
pub struct DataPacket {msg_id: u32,protocol: u8,body: Value,
}#[wasm_bindgen]
pub fn pack(msg_id: u32, protocol: u8, body: JsValue) -> Result<Box<[u8]>, JsValue> {let body: Value = from_value(body).map_err(|err| JsValue::from_str(&err.to_string()))?;let packet = DataPacket { msg_id, protocol, body };let json_bytes = serde_json::to_vec(&packet.body).map_err(|err| JsValue::from_str(&err.to_string()))?;let json_length = json_bytes.len() as u32;let mut buffer = Vec::with_capacity(4 + 4 + 1 + json_bytes.len());let mut msg_id_buf = [0u8; 4];BigEndian::write_u32(&mut msg_id_buf, packet.msg_id);buffer.extend_from_slice(&msg_id_buf);let mut length_buf = [0u8; 4];BigEndian::write_u32(&mut length_buf, json_length);buffer.extend_from_slice(&length_buf);buffer.push(packet.protocol);buffer.extend_from_slice(&json_bytes);Ok(buffer.into_boxed_slice())
}#[wasm_bindgen]
pub fn unpack(data: &[u8]) -> Result<JsValue, JsValue> {let mut cursor = Cursor::new(data);let mut msg_id_buf = [0u8; 4];cursor.read_exact(&mut msg_id_buf).map_err(|err| JsValue::from_str(&err.to_string()))?;let msg_id = BigEndian::read_u32(&msg_id_buf);let mut length_buf = [0u8; 4];cursor.read_exact(&mut length_buf).map_err(|err| JsValue::from_str(&err.to_string()))?;let json_length = BigEndian::read_u32(&length_buf) as usize;let mut protocol_buf = [0u8; 1];cursor.read_exact(&mut protocol_buf).map_err(|err| JsValue::from_str(&err.to_string()))?;let protocol = protocol_buf[0];let mut json_bytes = vec![0u8; json_length];cursor.read_exact(&mut json_bytes).map_err(|err| JsValue::from_str(&err.to_string()))?;let body: Value = serde_json::from_slice(&json_bytes).map_err(|err| JsValue::from_str(&err.to_string()))?;let packet = DataPacket { msg_id, protocol, body };to_value(&packet).map_err(|err| JsValue::from_str(&err.to_string()))
}#[wasm_bindgen]
pub fn process_bytes(data: Uint8Array) -> String {// 获取 Uint8Array 的长度let data_len = data.length() as usize;let mut bytes = Vec::with_capacity(data_len);// 将 Uint8Array 的内容复制到 Rust 向量中unsafe {bytes.set_len(data_len);data.copy_to(&mut bytes);}// 将字节数组转换为字符串match String::from_utf8(bytes) {Ok(s) => s,Err(e) => {web_sys::console::error_1(&format!("转换字节到字符串失败: {}", e).into());String::from("转换失败")},}
}

介绍两种打包方式一种就是cargo 打包,第二种 wasm-pack 工具打包

1.cargo 打包安装目标平台,可以通过命令查看 rust 覆盖的平台,还是很强的基本覆盖所有平台,命令查看方式 rustup target list

rustup target add wasm32-unknown-unknown
rustup show 确认是否安装成功 或者  rustup target list --installed 
cargo build --target wasm32-unknown-unknown
# 生成 target/debug 有.wasm 后缀

为了让js直接调用,由于我们使用了 wasm_bindgen 所以也要安装对应的插件,把js封装让开发人员直接调用

cargo install wasm-bindgen-cli
cargo install --list 查看
然后使用命令
wasm-bindgen target/wasm32-unknown-unknown/debug/rust_wasm.wasm --out-dir ./out --target web
这个web 是对应的平台使用方式,out 就是js目录bundler:编译成给webpack之类的脚手架使用
web:编译成web可直接使用
nodejs:编译成可通过require来加载的node模块
deno:编译成可通过import加载的deno模块
no-modules:跟web类似,但是更旧,且不能使用es模块
  1. 直接使用其wasm-pack 更好,支持ts,更多的其他版本
cargo install wasm-packwasm-pack build --target web  # 这个直接生成了pkg目录bundler:编译成给webpack之类的脚手架使用
web:编译成web可直接使用
nodejs:编译成可通过require来加载的node模块
deno:编译成可通过import加载的deno模块
no-modules:跟web类似,但是更旧,且不能使用es模块

现在演示下使用web 版本的wasm

在项目pkg 同一级创建一个index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>使用Rust和WebAssembly</title>
</head>
<body>
Hello, World!
</body>
<script type="module">import init, { pack,unpack } from './pkg/rust_wasm.js';const run = async () => {await init();  // 指定远程的 .wasm 文件const result = fib(10);console.log("result:",result);// 示例: 调用 pack 函数const packet = pack(1, 1, JSON.stringify({ u: 3333 }));console.log('Packed data:', packet);// 示例: 调用 unpack 函数const unpackedData = unpack(packet);console.log('Unpacked data:', unpackedData);}run();
</script>
</html>

由于wasm 不能是加载本地文件方式,所以需要启动个http服务

在.index.html 和pkg 和 index.html 同一级,访问域名看终端输出看终端输出
python3 -m http.server
默认是 8000 端口, 访问 http://127.0.0.1:8000/ ,

如果客户端项目node 和这前端项目支持 webpack 打包的可以打出对应的 wasm

参考链接:
https://github.com/hunter-ji/Blog/issues/72#issue-1756474747

https://juejin.cn/post/7156102433581383716

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com