【问题标题】:Caught between a lifetime and an FFI place夹在一生和 FFI 的地方之间
【发布时间】:2015-01-28 03:12:27
【问题描述】:

我陷入了两个不同的问题/错误之中,无法想出一个体面的解决方案。任何帮助将不胜感激

上下文、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 包装代码中重复出现。

【问题讨论】:

  • 如果您提供了您想要工作的完整代码,对此发表评论会更容易。我怀疑 Stack Overflow 也不是解决这个问题的好地方;我建议你试试 Rust IRC 频道。
  • 作为第一个错误的解决方法,您可能需要先查看参考。而不是foo: T = unsafe { *ptr },试试foo: &amp;mut T = unsafe { &amp;mut *ptr }(为了清楚起见,添加了冗余类型注释)。
  • 我想我遇到了这样的事情,在我的特殊情况下,我能够通过为该类型实现 Copy 来解决它(这很有意义),我猜你会是CassResult.
  • 叮叮叮。考虑到我的困境,Shep 对此 ICE 的解决方法是(我相信)理想的答案。 FWIW,正在进行中的代码是github.com/tupshin/cql-ffi-safe
  • 或不完全。添加了一个编辑。

标签: rust ffi lifetime


【解决方案1】:

只是部分答案:使用"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,但我确实喜欢流迭代器的想法。如果可行,我会尝试并接受这个答案。 tyvm
【解决方案2】:

回答我自己的问题。唯一体面的答案是绕过原来的ICE,但作为thepowersgang cmets,现在执行此操作的正确方法是使用:std::ptr::read,因此使用该方法,无需ICE,并希望取得进展。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-19
    • 1970-01-01
    • 2019-07-31
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    • 2014-11-06
    • 2015-12-11
    相关资源
    最近更新 更多