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模块
- 直接使用其wasm-pack 更好,支持ts,更多的其他版本
cargo install wasm-pack
wasm-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
原文地址:https://blog.csdn.net/qq_36517296/article/details/140583625
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!