Module ffi_helpers::error_handling [−][src]
Expand description
Common error handling routines.
The main error handling method employed is a thread-local variable called
LAST_ERROR
which holds the most recent error as well as some convenience
functions for getting/clearing this variable.
The theory is if a function fails then it should return an “obviously
invalid” value (typically -1
or 0
when returning integers or NULL
for
pointers, see the Nullable
trait for more). The user can then check for
this and consult the most recent error for more information. Of course that
means all fallible operations must update the most recent error if they
fail and that you must check the returned value of any fallible operation.
While it isn’t as elegant as Rust’s monad-style Result<T, E>
with ?
and
the various combinators, it actually turns out to be a pretty robust error
handling technique in practice.
Note: It is highly recommended to have a skim through libgit2’s error handling docs. The error handling mechanism used here takes a lot of inspiration from
libgit2
.
Examples
The following shows a full example where our write_data()
function will
try to write some data into a buffer. The first time through
use libc::{c_char, c_int};
use std::slice;
use ffi_helpers::error_handling;
fn main() {
if unsafe { some_fallible_operation() } != 1 {
// Before we can retrieve the message we need to know how long it is.
let err_msg_length = error_handling::last_error_length();
// then allocate a big enough buffer
let mut buffer = vec![0; err_msg_length as usize];
let bytes_written = unsafe {
let buf = buffer.as_mut_ptr() as *mut c_char;
let len = buffer.len() as c_int;
error_handling::error_message_utf8(buf, len)
};
// then interpret the message
match bytes_written {
-1 => panic!("Our buffer wasn't big enough!"),
0 => panic!("There wasn't an error message... Huh?"),
len if len > 0 => {
buffer.truncate(len as usize - 1);
let msg = String::from_utf8(buffer).unwrap();
println!("Error: {}", msg);
}
_ => unreachable!(),
}
}
}
/// pretend to do some complicated operation, returning whether the
/// operation was successful.
#[no_mangle]
unsafe extern "C" fn some_fallible_operation() -> c_int {
match do_stuff() {
Ok(_) => 1, // do_stuff() always errors, so this is unreachable
Err(e) => {
ffi_helpers::update_last_error(e);
0
}
}
}
Functions
Clear the LAST_ERROR
.
Peek at the most recent error and get its error message as a Rust String
.
Peek at the most recent error and write its error message (Display
impl)
into the provided buffer as a UTF-8 encoded string.
Peek at the most recent error and write its error message (Display
impl)
into the provided buffer as a UTF-16 encoded string.
Get the length of the last error message in bytes when encoded as UTF-8, including the trailing null.
Get the length of the last error message in bytes when encoded as UTF-16, including the trailing null.
Take the most recent error, clearing LAST_ERROR
in the process.
Update the thread_local
error, taking ownership of the Error
.