首页 > 解决方案 > 创建一个容器结构包含两个字段,从一个引用到另一个

问题描述

情况有点混乱。我正在尝试使用odbc-api从 odbc 数据源查询结果,并将函数包装到 ffi。

odbc-api 定义了以下结构,

struct Envirnoment {...}
struct Connection<'c> {...}


impl Envirnoment {
    pub fn connect_with_connection_string(
        &self,
        connection_string: &str,
    ) -> Result<Connection<'_>, Error> {...}
}

对于我的情况,在 C 端,create_connection调用以返回 rust 中定义的连接处理程序。

#[no_mangle]
pub unsafe extern "C" fn create_connection(c_str: *const c_char) -> *mut Connection<'static> {
    let env = Environment::new().unwrap();
    let conn = env.connect_with_connection_string(CStr::from_ptr(c_str).to_str().unwrap()).unwrap();
    Box::into_raw(Box::new(conn))
}

编译器返回错误如下。

error[E0515]: cannot return value referencing local variable `env`
  --> odbc-demo/src/main.rs:37:5
   |
36 |     let conn = env.connect_with_connection_string(CStr::from_ptr(c_str).to_str().unwrap()).unwrap();
   |                --- `env` is borrowed here
37 |     Box::into_raw(Box::new(conn))
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

Connection 的生命周期无法解决,因为env在函数返回时被丢弃。当处理程序暴露给 ffi 时,如何绑定envconnection进入单个结构?是std::pin解决方案吗?如何在处理程序结构中定义连接的生命周期?

此外,我想制作env一个全局静态 Arc 对象,以便我可以从单个 env 创建多个连接。

lazy_static!{
    static ref ENV: Arc<Envirnoment> = Arc::new(Envirnoment::new().unwrap());
}

那么如何定义handler struct呢?

我预期的处理程序看起来像

#[repr(C)]
struct ConnectionHandler{
    env: Arc<Envirnoment>,
    conn: Connection<'_>,
}

更新:

我期望的处理程序是在堆栈上捕获生命周期有界对象和有界对象,以延长整个生命周期并将所有权转移给 ffi。我认为std::pin应该按预期工作,因为预期的处理程序像异步函数一样工作。

在重新考虑了我的 FFI 实现的整个设计之后,我的设计结果是连接对象保持在(绿色)线程中,并用于std::sync::mpsc将控制权转移给 ffi。

标签: rust

解决方案


推荐阅读