如何处理将 usize 传递给需要 uint32_t 的 C 函数?

How to handle passing usize to a C function that expects uint32_t?

我正在围绕 C 库编写 Rust 包装器。 C库提供了以下功能:

void lib_foo(const unsigned char *buf, uint32_t buf_len);

我创建了以下 extern 包装器:

fn lib_foo(buf: *const u8, buf_len: u32);

和以下高级包装器:

pub fn foo(buf: &[u8]) {
    unsafe { lib_foo(buf.as_ptr(), buf.len() as u32) }
}

但是,从 usizebuf.len() 的类型)到 u32 的转换可能会导致大小被截断。处理此问题的最佳方法是什么?

  • 如果使用 lib_foo 对 read/write 块有意义,请将其包装在一个循环中,该循环处理 2**32 的块(以递增的偏移量),然后处理其余部分。在大多数情况下它会跳过循环,但在特殊情况下,它只会多次调用 lib_foo
  • 如果 lib_foo 可以接受截断行为,请截断并以某种方式告诉用户
  • 如果不是,大声抱怨 if len >= 2**32

首先,请使用 libc 类型的箱子。

即:extern fn lib_foo(buf: *const libc::c_uchar, buf_len: libc::uint32_t);

虽然略长,但会避免假设(unsigned char映射到u8)并自动翻译。


然后,进入高级包装器。

没有任何假设,最简单的解决方案是恐慌,并记录下来。

/// Calls `lib_foo`, ...
///
/// # Panics
///
/// If the size of the buffer is strictly greater than 2^32-1 bytes.
pub fn foo(buf: &[u8]) {
    assert!(buf.len() <= (std::u32::MAX as usize));

    unsafe { lib_foo(buf.as_ptr() as *const _, buf.len() as libc::uint32_t) }
}

然后,根据域的不同,可能会出现其他选项:

  • 饱和度可能是一个选项(使用 std::cmp::min
  • 重复调用可能是另一个
  • ...

在任何情况下,如果用户可以观察到行为差异,文档