如何从Rust侧测试对外暴露的C回调函数接口?
问题
我正在查看一个用Rust编写的C API,该API使用回调函数,其实现模式如下:
type FooCallback = extern "C" fn(data: &FooData, context: FooContext); trait FooCallbackExt { fn call(&self, data: FooData, context: FooContext); } impl FooCallbackExt for FooCallback { fn call(&self, data_in: FooData, context: FooContext) { // Doing cool things } }
我已能从C侧创建如下回调函数进行测试:
void callback(const FooData* data, FooContext context)
现在我希望从Rust侧尽可能贴近暴露的C接口进行测试,以排查疑似出现在Rust中的问题。接收该回调的Rust函数为:
fn foo(&mut self, callback: FooCallback, context: FooContext)
但我不清楚如何从Rust侧创建符合要求的回调。请问是否需要创建某种转换层或中间层?或者能否创建Rust版本的回调并让二者共用同一trait?
解答
不需要额外的转换层,直接在Rust里定义符合extern "C"调用约定的函数就能匹配FooCallback类型,直接传给foo函数即可。
1. 编写符合要求的Rust回调函数
直接定义带有extern "C"标记的函数,参数签名和FooCallback完全一致:
extern "C" fn rust_callback(data: &FooData, context: FooContext) { // 编写你的测试逻辑,比如验证数据内容、打印调试信息等 println!("Received FooData: {:?}", data); }
2. 直接传递给foo函数
这个函数的类型正好是FooCallback,可以直接作为参数传入:
// 假设已创建Foo类型实例 let mut foo_instance = Foo::new(); foo_instance.foo(rust_callback, some_context);
关于共用Trait的说明
如果只是要贴近C接口做测试,上述方式完全足够。如果需要让Rust侧的自定义类型(比如带状态的结构体、闭包)也适配该回调接口,才需要扩展FooCallbackExt或做封装,但要注意C ABI的限制:C回调无法直接携带Rust堆分配状态,通常需要将状态指针存入FooContext,再在回调内解引用使用。
内容的提问来源于stack exchange,提问作者munger
相关产品推荐
相关产品推荐

