如何将特征对象的一部分传递给 C

How to pass a slice of trait objects to C

我最近一直在开发一个库,我想为它制作 C 绑定。该库中的一个结构 returns 用户的特征对象片段。这是函数定义的样子:

pub fn controllers(&self) -> &[Box<dyn Controller>] {
    &self.controllers
}

我不确定如何翻译这个。 C 代码将 而不是 插入这些动态对象中。它只会将它们传递回 Rust 代码,即

pub fn controller_get_name(controller: *const dyn Controller) -> *const c_char {
    let controller = controller.as_ref();
    controller.get_name().as_ptr();

}

目前,我有这个:

#[no_mangle]
pub extern "C" fn libvibrant_instance_get_controllers(instance: *mut Instance,
                                                      mut controllers: *const dyn Controller,
                                                      len: *mut usize) {
    assert!(!instance.is_null());
    assert!(!len.is_null());

    let instance = unsafe { instance.as_ref().unwrap() };
    controllers = instance.controllers().as_ptr();
    unsafe {
        *len = instance.controllers().len();
    }
}

但显然,这不起作用,因为 as_ptr 返回的是 *const Box<dyn Controller> 而不是 *const dyn Controller。我可以在这里做什么?

写C绑定时,应该从C端考虑,想提供什么操作,尽可能隐藏实现。

比如你说C代码会用trait对象回调Rust;并且您似乎想将它们作为 (pointer, length) 对传递给 C,以便 C 可以迭代它们。然而,这意味着 C 需要知道每个特征对象有多大(比单个指针大;共享切片也是如此)。

相反,我会为集合和相关函数提供一个不透明的句柄以对其进行迭代。只有当性能非常重要时,我才会让 C 知道每个元素的大小(这意味着 ABI 将取决于 Rust 如何表示 DST)。

有关技术细节,请查看 等问题。