我正在围绕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) }
}
但是,从usize
(buf.len()
的类型)到u32
的强制转换可能会导致大小被截断。解决这个问题的最佳方法是什么?
答案 0 :(得分:4)
首先,请使用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
)在任何情况下,如果行为的差异对于用户是可观察的,文档。
答案 1 :(得分:0)
lib_foo
读取/写入块是有意义的,请将其包装在一个循环中,该循环处理2 ** 32的块(增加的偏移量),然后处理剩余部分。在大多数情况下,它会跳过循环,但在特殊情况下,它只会多次调用lib_foo
lib_foo
的可接受行为,请以某种方式截断并告诉用户