Idiomatic use of Result type and -1 error returns from c functions

I'm writing a library that makes heavy use of c functions that return -1 on error and put the error condition in errno. I wrote a macro that handles the conversion to a Result type:

macro_rules! ctry {                                                                 
    ( $x:expr ) => {                                                                
        match $x {                                                                  
            -1 => Err(Error::last_os_error()),                                      
            retval => Ok(retval)                                                    
        }                                                                           
    }                                                                               
} 

I'm early in my use of Rust but I knew full well when I wrote this that I would find that the std library would hacve something similar. When I did go back and look at how the std library solved this problem, I was surprised to discover a pair of functions (cvt & cvt_r) rather than a macro (in libstd/sys/unix/mod.rs) .

pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
    if t.is_minus_one() {
        Err(io::Error::last_os_error())
    } else {
        Ok(t)
    }
}

pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
    where T: IsMinusOne,
          F: FnMut() -> T
{
    loop {
        match cvt(f()) {
            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
            other => return other,
        }
    }
}

I hadn't yet handled PC loser-ing, so I get why there are two functions (to retry the call if it is interrupted). What I don't yet understand is why this is better implemented as a function rather than a macro. Can somebody explain?

In Rust, the try macro will return from the function where you called the C function. The cvt function will just convert the return value to a Result. If you want to check the error, you'll need to use the function.

Your ctry macro doesn't return implicitly, which means it could have been written as a function. In general: don't write a macro for what you could do with a function.

4 Likes

Thanks! ctry was definitely a bad name.