Hacker News new | ask | show | jobs
by Animats 3074 days ago
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 and there will be some awful C APIs you can't describe. That's a good indication said C API is trouble.

1 comments

What would make this "declarative way to talk about C interfaces" less error prone than something like this?

    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<usize, ReadError> {
            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.)
That's not bad. It would be useful to be able to use some kind of "C slice" in an extern fn declaration, so you could talk about arrays, rather than pointers. Same function call code, but more Rust-line syntax. Then you don't need unsafe imperative code at all.

This would put all the memory-risky stuff in declarations of external functions.