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?