夹在一生和 FFI 之间

Caught between a lifetime and an FFI place

我夹在两个不同的 issues/bugs 之间,想不出一个合适的解决方案。任何帮助将不胜感激

上下文、FFI 和调用大量 C 函数,并将 C 类型包装在 rust 结构中。

第一个问题是ICE: this path should not cause illegal move

这迫使我使用 & 引用来完成我所有的结构包装,如:

pub struct CassResult<'a> {
    result:&'a cql_ffi::CassResult
}

而不是更简单、更可取的:

pub struct CassResult {
    result:cql_ffi::CassResult
}

否则代码如下:

pub fn first_row(&self) -> Result<CassRow,CassError> {unsafe{
    Ok(CassRow{row:*cql_ffi::cass_result_first_row(self.result)})
}}

将导致:

error: internal compiler error: this path should not cause illegal move
Ok(CassRow{row:*cql_ffi::cass_result_first_row(self.result)})
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

因此,我继续使用生命周期托管引用包装所有内容,并且在我尝试实现迭代器之前一切都不可怕。在这一点上我看不出绕过 this problem.

method next has an incompatible type for trait: expected concrete lifetime, found bound lifetime parameter

鉴于这两个相互矛盾的问题,我完全陷入困境,找不到任何方法来围绕类似 FFI 迭代器的构造实现适当的 Rust 迭代器。

编辑:根据 Shep 的建议,我得到:

pub struct CassResult {
    pub result:cql_ffi::CassResult
}

pub fn get_result(&mut future:future) -> Option<CassResult> {unsafe{
    let result:&cql_ffi::CassResult = &*cql_ffi::cass_future_get_result(&mut future.future);
    Some(CassResult{result:*result})
}}

然后得到:

error: cannot move out of borrowed content
Some(CassResult{result:*result}

有什么方法可以使该模式起作用吗?它在整个 FFI 包装代码中重复出现。

只有部分答案:使用 "streaming iterator" trait and macro.

我在围绕 C mysql API 进行 Rust 绑定时遇到了类似的问题。结果是这样的代码,而不是原生的 for 语法:

let query = format!("SELECT id_y, value FROM table_x WHERE id = {}", id_x);
let res = try!(db::run_query(&query));
streaming_for!( row, res.into_iter(), {
    let id_y: usize = try!(row.convert::<usize>(0));
    let value: f64 = try!(row.convert::<f64>(1));
});

此处 res 保存结果并释放内存。 row 的生命周期与 res:

相关联
/// Res has an attached lifetime to guard an internal pointer.
struct Res<'a>{ p: *mut c_void }
/// Wrapper created by into_iter()
struct ResMoveIter<'a>{ res: Res<'a> }
impl<'a> /*StreamingIterator<'a, Row<'a>> for*/ ResMoveIter<'a>{
    /// Get the next row, or None if no more rows
    pub fn next(&'a mut self) -> Option<Row<'a>>{
        ...
    }
}
#[unsafe_destructor]
impl<'a> Drop for Res<'a>{
    fn drop(&mut self){
        ...
    }
}

回答我自己的问题。唯一合适的答案是绕过原始 ICE 的方法,但正如权力帮派评论的那样,现在执行此操作的正确方法是使用 :std::ptr::read,因此使用该方法,无需 ICE,希望如此进步。