The situation is a bit of confusing.
I'm trying to use odbc-api
to query result from odbc datasources, and wrapped the functions into ffi.
odbc-api defines following structs as below,
struct Envirnoment {...}
struct Connection<'c> {...}
impl Envirnoment {
pub fn connect_with_connection_string(
&self,
connection_string: &str,
) -> Result<Connection<'_>, Error> {...}
}
For my situation, on the C side, create_connection
is called to return a connection handler defines in 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))
}
The compiler returns error as below.
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
The lifetime of Connection cannot be resolved, since env
is dropped when function returns. How can I bind env
and connection
into a single struct as a handler exposes to ffi? Is std::pin
the solution? How to define the lifetime of connection in the handler struct?
Furthermore, I'd like to make env
into a global static Arc object, so that I can create multiple connection from the single env.
lazy_static!{
static ref ENV: Arc<Envirnoment> = Arc::new(Envirnoment::new().unwrap());
}
Then how to define the handler struct?
My expected handler looks like
#[repr(C)]
struct ConnectionHandler{
env: Arc<Envirnoment>,
conn: Connection<'_>,
}
Update:
My expected handler is to capture a lifetime bounded object and the bounded object, on stack, to extend the whole lifetime and transfer the ownership to ffi. I think std::pin
should work as expect, since the expected handler works like an async function.
After reconsidering the whole design of my FFI implements, my design turns out that the connection object maintains in (green) thread, and use std::sync::mpsc
to transfer the control to ffi.