Rust WASM运行时wasmtime的C API宏库wasmtime-c-api-macros使用指南:实现高效WebAssembly接口绑定
Rust WASM运行时wasmtime的C API宏库wasmtime-c-api-macros使用指南:实现高效WebAssembly接口绑定
安装
在项目目录中运行以下Cargo命令:
cargo add wasmtime-c-api-macros
或者在Cargo.toml中添加以下行:
wasmtime-c-api-macros = "34.0.2"
使用示例
下面是一个完整的示例,展示如何使用wasmtime-c-api-macros来绑定WebAssembly函数:
use wasmtime_c_api_macros::wasmtime_c_api;
// 定义一个Rust函数,将被暴露给WebAssembly
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
a + b
}
// 使用wasmtime_c_api宏生成C API绑定
wasmtime_c_api! {
// 定义模块名
module "math" {
// 暴露add函数给WebAssembly
export "add" fn add(a: i32, b: i32) -> i32;
}
}
fn main() {
// 初始化wasmtime引擎
let engine = wasmtime::Engine::default();
let mut store = wasmtime::Store::new(&engine, ());
// 使用生成的绑定创建模块
let module = wasmtime::Module::new(&engine, wasmtime_c_api::math::MODULE).unwrap();
// 实例化模块
let instance = wasmtime::Instance::new(&mut store, &module, &[]).unwrap();
// 获取add函数并调用
let add = instance.get_typed_func::<(i32, i32), i32>(&mut store, "add").unwrap();
let result = add.call(&mut store, (2, 3)).unwrap();
println!("2 + 3 = {}", result); // 输出: 2 + 3 = 5
}
高级用法
wasmtime-c-api-macros还支持更复杂的绑定场景:
use wasmtime_c_api_macros::wasmtime_c_api;
// 定义复杂数据结构
#[repr(C)]
pub struct Point {
x: f32,
y: f32,
}
// 实现复杂函数
#[no_mangle]
pub extern "C" fn distance(p1: Point, p2: Point) -> f32 {
let dx = p1.x - p2.x;
let dy = p1.y - p2.y;
(dx * dx + dy * dy).sqrt()
}
wasmtime_c_api! {
module "geometry" {
// 定义结构体类型
type Point {
x: f32,
y: f32,
}
// 暴露复杂函数
export "distance" fn distance(p1: Point, p2: Point) -> f32;
}
}
// 使用方式与简单示例类似,但可以处理复杂数据结构
完整示例demo
下面是一个结合了基础用法和高级用法的完整示例:
use wasmtime_c_api_macros::wasmtime_c_api;
// 基础数学运算
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
a + b
}
// 几何运算
#[repr(C)]
pub struct Point {
x: f32,
y: f32,
}
#[no_mangle]
pub extern "C" fn distance(p1: Point, p2: Point) -> f32 {
let dx = p1.x - p2.x;
let dy = p1.y - p2.y;
(dx * dx + dy * dy).sqrt()
}
// 生成所有绑定
wasmtime_c_api! {
module "math" {
export "add" fn add(a: i32, b: i32) -> i32;
}
module "geometry" {
type Point {
x: f32,
y: f32,
}
export "distance" fn distance(p1: Point, p2: Point) -> f32;
}
}
fn main() {
let engine = wasmtime::Engine::default();
let mut store = wasmtime::Store::new(&engine, ());
// 测试数学模块
let math_module = wasmtime::Module::new(&engine, wasmtime_c_api::math::MODULE).unwrap();
let math_instance = wasmtime::Instance::new(&mut store, &math_module, &[]).unwrap();
let add_func = math_instance.get_typed_func::<(i32, i32), i32>(&mut store, "add").unwrap();
let result = add_func.call(&mut store, (5, 7)).unwrap();
println!("5 + 7 = {}", result);
// 测试几何模块
let geo_module = wasmtime::Module::new(&engine, wasmtime_c_api::geometry::MODULE).unwrap();
let geo_instance = wasmtime::Instance::new(&mut store, &geo_module, &[]).unwrap();
let distance_func = geo_instance.get_typed_func::<(Point, Point), f32>(&mut store, "distance").unwrap();
let p1 = Point { x: 1.0, y: 2.0 };
let p2 = Point { x: 4.0, y: 6.0 };
let dist = distance_func.call(&mut store, (p1, p2)).unwrap();
println!("两点之间的距离: {}", dist);
}
许可证
Apache-2.0 WITH LLVM-exception
1 回复
以下是基于您提供的内容整理的完整示例demo:
完整示例demo
// 引入必要的库和宏
use wasmtime_c_api_macros::{wasmtime_c_api, wasmtime_export};
use wasmtime::{Engine, Store, Linker, Module, Instance};
use std::ffi::CString;
// 1. 定义一个计数器API结构体
#[wasmtime_c_api]
struct CounterApi {
value: i32,
}
#[wasmtime_export]
impl CounterApi {
// 构造函数
pub fn new(initial: i32) -> Self {
CounterApi { value: initial }
}
// 增加计数器值
pub fn increment(&mut self) -> i32 {
self.value += 1;
self.value
}
// 带参数的加法操作
pub fn add(&mut self, num: i32) -> i32 {
self.value += num;
self.value
}
// 获取当前值
pub fn get(&self) -> i32 {
self.value
}
}
// 2. 定义字符串处理API
#[wasmtime_c_api]
struct StringApi;
#[wasmtime_export]
impl StringApi {
// 反转字符串
pub fn reverse(input: &str) -> String {
input.chars().rev().collect()
}
// 处理C字符串
pub fn process_c_string(input: *const libc::c_char) -> *mut libc::c_char {
let c_str = unsafe { std::ffi::CStr::from_ptr(input) };
let rust_str = c_str.to_str().unwrap();
let processed = format!("Processed: {}", rust_str);
CString::new(processed).unwrap().into_raw()
}
}
// 3. 主函数集成WASM
fn main() -> wasmtime::Result<()> {
// 创建WASM引擎和存储
let engine = Engine::default();
let mut store = Store::new(&engine, ());
// 创建链接器并添加我们的API
let mut linker = Linker::new(&engine);
CounterApi::add_to_linker(&mut linker, |context| context)?;
StringApi::add_to_linker(&mut linker, |context| context)?;
// 加载并实例化WASM模块
let module = Module::from_file(&engine, "demo.wasm")?;
let instance = linker.instantiate(&mut store, &module)?;
// 获取WASM函数并调用
let add_func = instance.get_func(&mut store, "wasm_add").unwrap();
let result = add_func.call(&mut store, &[5.into()])?;
println!("WASM调用结果: {:?}", result);
Ok(())
}
// 4. 错误处理示例
#[wasmtime_c_api]
struct FileApi;
#[wasmtime_export]
impl FileApi {
pub fn read_file(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
}
// 5. 回调函数示例
type MathCallback = extern "C" fn(i32, i32) -> i32;
#[wasmtime_c_api]
struct CallbackApi;
#[wasmtime_export]
impl CallbackApi {
pub fn calculate(a: i32, b: i32, callback: MathCallback) -> i32 {
callback(a, b)
}
}
示例说明
-
计数器API:
- 展示了基本的结构体定义和方法导出
- 包含初始化、修改和查询状态的方法
-
字符串处理API:
- 演示了如何处理Rust字符串和C字符串的相互转换
- 包含字符串反转和C字符串处理的示例
-
WASM集成:
- 展示如何将API绑定到WASM运行时
- 包含引擎初始化、模块加载和函数调用的完整流程
-
错误处理:
- 演示如何将Rust的错误类型自动转换为C API可处理的格式
-
回调函数:
- 展示如何从Rust调用C端提供的回调函数
这个完整示例涵盖了您提供的所有关键功能点,并保持了代码的清晰性和实用性。您可以根据实际需求调整或扩展这些示例。