我正在编写一个外部函数接口 (ffi),以将预先存在的 C++ 库的 API 公开给我正在编写的一些新 Rust 代码。cxx我为此使用 Rust模块。
我遇到了一些相关的问题Pin(我必须承认我没有完全掌握这个主题)。
我的 C++ 模块有一个 API,它从拥有这些包含对象的主对象公开指向某些包含对象的指针。这是一个人为的例子:
// test.hpp
#include <string>
#include <memory>
class Row {
std::string row_data;
public:
void set_value(const std::string& new_value) {
this->row_data = new_value;
}
};
class Table {
Row row;
public:
Table() : row() {};
Row* get_row() {
return &this->row;
}
};
inline std::unique_ptr<Table> make_table() {
return std::make_unique<Table>();
}
Run Code Online (Sandbox Code Playgroud)
这个想法是,您创建一个Table对象,然后该对象允许您获取指向它的指针Row,以便您可以操作它。
我创建 Rust FFI 的尝试如下所示:
// main.rs
use std::pin::Pin;
use cxx::let_cxx_string;
#[cxx::bridge] …Run Code Online (Sandbox Code Playgroud) 我有使用数据调用 Rust 代码的 C++ 代码。它知道将数据发送到哪个对象。下面是 C++ 回调的 Rust 函数示例:
extern "C" fn on_open_vpn_receive(
instance: Box<OpenVpn>,
data: *mut c_uchar,
size: *mut size_t,
) -> u8
Run Code Online (Sandbox Code Playgroud)
它将指针作为 a 接收Box,因此我创建了一个函数openvpn_set_rust_parent来设置 C++ 必须回调的对象。这个对象是一个指向自身的指针。我正在使用,Pin因此Box不会重新分配到其他地方,从而使 C++ 调用无效地址。
impl OpenVpn {
pub fn new() -> Pin<Box<OpenVpn>> {
let instance = unsafe { interface::openvpn_new(profile.as_ptr()) };
let o = OpenVpn { instance: instance };
let p = Box::pin(o);
unsafe {
interface::openvpn_set_rust_parent(o.instance, p.as_ptr());
};
p
}
}
Run Code Online (Sandbox Code Playgroud)
签名:
pub fn openvpn_set_rust_parent(instance: *mut …Run Code Online (Sandbox Code Playgroud)