Module ffi_helpers::error_handling
[−]
[src]
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
#[macro_use] extern crate ffi_helpers; extern crate failure; extern crate libc; 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_last_error |
Clear the |
error_message |
Peek at the most recent error and get its error message as a Rust |
error_message_utf8⚠ |
Peek at the most recent error and write its error message ( |
error_message_utf16⚠ |
Peek at the most recent error and write its error message ( |
last_error_length |
Get the length of the last error message in bytes when encoded as UTF-8, including the trailing null. |
last_error_length_utf16 |
Get the length of the last error message in bytes when encoded as UTF-16, including the trailing null. |
take_last_error |
Take the most recent error, clearing |
update_last_error |
Update the |