2个版本
0.1.1 | 2024年1月5日 |
---|---|
0.1.0 | 2023年12月16日 |
#1829 在 过程宏
每月585次下载
用于 2 crates
35KB
603 行
FFI
此crate通过提供属性#[ffi]
帮助通过FFI将Rust代码暴露给其他语言,特别是C语言,该属性会自动实现从C兼容函数指针到Rust impl
方法的调用转发。
这在编写可能在C程序(如QEMU)中通过dlopen
调用的Rust共享库时尤其有用。
示例
在这个例子中,假设run_callback
在一个你不拥有的C库中。然而,你希望使用回调注册函数的通用userdata
参数来调用你的结构实例。 ffi
允许你将你的impl
的方法作为C FFI兼容函数导出,这样你就可以轻松地在两种语言之间进行回调。
ffi
对C代码调用你的Rust代码时预期的回调类型参数顺序没有假设,因此它使得根据你的需要自定义生成变得很容易。它还提供了用于自动推导从原始指针(如From<*mut T> for &mut Foo
)转换的实用工具。
use ffi::ffi;
extern "C" fn run_callback(
callback: extern "C" fn(*mut std::ffi::c_void, i32, i32, i32) -> i32,
data: *mut std::ffi::c_void,
) -> i32 {
callback(data, 1, 2, 3)
}
extern "C" fn run_callback_reverse(
callback: extern "C" fn(i32, i32, i32, *mut std::ffi::c_void) -> i32,
data: *mut std::ffi::c_void,
) -> i32 {
callback(1, 2, 3, data)
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Vec3 {
x: i32,
y: i32,
z: i32,
}
#[ffi(from_ptr, self_ty = "*mut std::ffi::c_void")]
impl Vec3 {
#[ffi(arg(self), arg(rest))]
fn add(&mut self, x: i32, y: i32, z: i32) -> i32 {
self.x += x;
self.y += y;
self.z += z;
self.x + self.y + self.z
}
#[ffi(arg(rest), arg(self))]
fn add_reverse_args(&mut self, x: i32, y: i32, z: i32) -> i32 {
self.add(x, y, z)
}
}
fn main() {
let mut v = Vec3 { x: 1, y: 2, z: 3 };
run_callback(vec3::add, &mut v as *mut Vec3 as *mut _);
assert_eq!(v, Vec3 { x: 2, y: 4, z: 6 })
run_callback_reverse(vec3::add_reverse_args, &mut v as *mut Vec3 as *mut _);
assert_eq!(v, Vec3 { x: 3, y: 6, z: 9});
}
依赖项
~0.8–1.3MB
~28K SLoC