Function ffi_support::call_with_result [−][src]
pub fn call_with_result<R, E, F>(
out_error: &mut ExternError,
callback: F
) -> R::Value where
F: UnwindSafe + FnOnce() -> Result<R, E>,
E: Into<ExternError>,
R: IntoFfi,
Call a callback that returns a Result<T, E>
while:
- Catching panics, and reporting them to C via
ExternError
. - Converting
T
to a C-compatible type usingIntoFfi
. - Converting
E
to a C-compatible error viaInto<ExternError>
.
This (or call_with_output
) should be in the majority of the FFI functions, see the crate
top-level docs for more info.
If your function doesn’t produce an error, you may use call_with_output
instead, which
doesn’t require you return a Result.
Example
A few points about the following example:
-
We need to mark it as
#[no_mangle] pub extern "C"
. -
We prefix it with a unique name for the library (e.g.
mylib_
). Foreign functions are not namespaced, and symbol collisions can cause a large number of problems and subtle bugs, including memory safety issues in some cases.
#[no_mangle] pub extern "C" fn mylib_print_string( // Strings come in as an `FfiStr`, which is a wrapper around a null terminated C string. thing_to_print: FfiStr<'_>, // Note that taking `&mut T` and `&T` is both allowed and encouraged, so long as `T: Sized`, // (e.g. it can't be a trait object, `&[T]`, a `&str`, etc). Also note that `Option<&T>` and // `Option<&mut T>` are also allowed, if you expect the caller to sometimes pass in null, but // that's the only case when it's currently to use `Option` in an argument list like this). error: &mut ExternError ) { // You should try to to do as little as possible outside the call_with_result, // to avoid a case where a panic occurs. ffi_support::call_with_result(error, || { let s = thing_to_print.as_str(); if s.is_empty() { // This is a silly example! return Err(BadEmptyString); } println!("{}", s); Ok(()) }) }