Earlier quoted context omitted.
> Rust's system for external C calls should be more like that and less about casts to raw pointers. It seems a rosy-eyed view to think that this would helping safety significantly, and would require a lot of effort: it's likely to be much lower pay-off than other things, like investing in, say, sanitizers or even just doing the work of writing safe wrappers for popular C libs, removing C FFI concerns from most people…
Of course you want to use Rust slices. Those map directly to the kind of C array I outlined. If you could declare a C API that way to Rust, you'd get the mapping without talking about pointers explicitly at all. What I'm arguing for is a declarative way to talk about C interfaces that is consistent with Rust's model. This is better than using "unsafe" to construct C-type raw pointers. Yes, this is more restrictive an…
extern fn read(fd: c_int, buf: *mut c_char, len: usize) -> isize;
pub fn read(fd: c_int, buf: &mut [c_char]) -> isize {
unsafe { read(fd, buf.as_mut(), buf.len()) }
}
Further, note that this is insufficient for an idiomatic Rust API. You would also want to wrap the file descriptor (perhaps not for all C APIs) and the return value (definitely applies to all C APIs). So it would really look more like this: pub struct File { fd: c_int }
impl File {
pub fn read(&self, buf: &mut [u8]) -> Result {
let r = unsafe { read(self.fd, buf.as_mut(), buf.len()) };
if r == -1 {
Err(ReadError::from(errno))
} else {
Ok(r as usize)
}
}
}
I can certainly imagine a way to do that declaratively, but not in a way that helps even this most basic of examples. (Also, note that constructing raw pointers is completely safe- `as_mut` for example.)