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,具体用法看官网文档

c 复制代码
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

sh 复制代码
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-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

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

相关推荐
花褪残红青杏小2 小时前
Rust图像处理第11节-故障风 RGB 通道偏移:错位错色制造电子故障
rust·webassembly·图形学
花褪残红青杏小3 小时前
Rust图像处理第10节-浮雕/雕刻滤镜:邻域差值生成凹凸效果
rust·webassembly·图形学
Rockbean3 小时前
10分钟Solana-性能web3-2.4 Rust 编程基础三:结构体、枚举、错误处理与集合
rust·web3·智能合约
doiito5 小时前
【Agent Harness】Gliding Horse 上下文感知与智能压缩:让 Agent 的“注意力”永不偏移
ai·rust·架构设计·系统设计·ai agent
花褪残红青杏小1 天前
Rust图像处理第9节-Sobel 边缘检测:第一个真正用卷积的算法
rust·webassembly·图形学
doiito1 天前
【Agent Harness】Gliding Horse L2 作战地图深度优化:给多 Agent 上下文装上“精准导航”
ai·rust·架构设计·系统设计·ai agent
花褪残红青杏小2 天前
Rust图像处理第8节-暗角 & 复古胶片特效:四周衰减中心高亮
rust·webassembly·图形学
独孤留白2 天前
从C到Rust:Rust 的 Trait 不是Interface,那是什么?
rust