Expand description
Alternative Rust bindings for libffi.
This crate is an alternative to the libffi-rs crate. The interface is similar, but
fiffi aims to be a slimmer version of libffi-rs with a smaller public interface and higher
test coverage. fiffi uses libffi-sys-rs for building and linking to the
underlying libffi library.
There are three main uses for this crate:
- Calling foreign functions that are not available at compile time using
Function - Creating function pointers to Rust closures using
Closure - Creating function pointers with arbitrary signatures chosen at run time using
DynamicClosure
§Examples
§Calling an FFI function with Function:
use fiffi::function::{Function, arg, ret};
use fiffi::types::Type;
extern "C" fn add(a: i32, b: i32) -> i32 {
a + b
}
let function = Function::new(
fiffi::fn_ptrize!(add),
&[Type::I32, Type::I32],
Some(&Type::I32),
);
let a = 19i32;
let b = 23i32;
let mut result = 0i32;
// SAFETY: `function` was built from `add` with matching argument and return types.
unsafe {
function.call([arg(&a), arg(&b)], ret(&mut result));
}
assert_eq!(result, 42);§Converting a Rust closure to a function pointer with Closure:
use fiffi::closure::Closure;
let offset = 5i32;
let add_offset = Closure::new(move |value: i32| value + offset);
// `add_offset.as_fn_ptr()` can now be called to get a function pointer to a function that adds
// `offset` to the `i32` argument it receives and returns the result.
// SAFETY: `add_offset` accepts one `i32` argument, returns `i32`, and remains alive while the
// function pointer is used.
let add_offset_fn = unsafe {
add_offset
.as_fn_ptr()
.into_fn::<extern "C" fn(i32) -> i32>()
};
assert_eq!(add_offset_fn(37), 42);§Creating a function pointer with a signature defined at run time using DynamicClosure:
use core::mem::MaybeUninit;
use fiffi::closure::DynamicClosure;
use fiffi::closure::dynamic::DynamicClosureCall;
use fiffi::types::Type;
fn add_offset_callback(mut call: DynamicClosureCall<i32>) {
let arg = call
.args()
.get(0)
.expect("This callback must be used with exactly one argument.");
if arg.ty() != &Type::I32 {
// **NOTE** This will abort instead of unwinding regardless of the crate's setting
// because Rust cannot unwind past libffi's `extern "C"` functions.
panic!("This callback can only be used with an `i32` argument.");
}
let mut value = MaybeUninit::<i32>::uninit();
// SAFETY: The argument's type is `i32`. The `copy_to` fully initializes `value`.
let result = unsafe {
arg.copy_to(&mut value);
value.assume_init()
} + call.context();
let ret = call.ret().expect("This callback expects a return value.");
if ret.ty() != &Type::I32 {
// **NOTE** This will abort instead of unwinding regardless of the crate's setting
// because Rust cannot unwind past libffi's `extern "C"` functions.
panic!("This callback can only be used with an `i32` return value.");
}
// SAFETY: The return value's type is `i32`.
unsafe {
ret.write(result);
}
}
let add_offset = DynamicClosure::new(add_offset_callback, &[Type::I32], Some(&Type::I32), 5);
// SAFETY: `add_offset` represents an `extern "C"` function that accepts one `i32` and returns
// an `i32`. `add_offset` remains alive while it is called.
let add_offset_fn = unsafe {
add_offset
.as_fn_ptr()
.into_fn::<extern "C" fn(i32) -> i32>()
};
assert_eq!(add_offset_fn(37), 42);§Features
closure- includeClosureandDynamicClosure. This feature is enabled by default.check_only- Speed up check builds by skipping the actual compilation of libffi.system- enableslibffi-sys’ssystemflag to dynamically link to libffi instead of compiling a static library. Note that certain functionality require version 3.5.0 of libffi, which may cause problems when using thesystemfeature.
§Panics
As a general rule fiffi functions do not panic. The exception is when allocating a new
Closure or DynamicClosure, however both types have constructors that return an error
instead of panicking if allocation fails.
Some safeguards to detect serious bugs in fiffi and/or libffi may also panic if a bug is
detected or a code path that is only reachable through improper use of unsafe is reached.
Modules§
- abi
- This module defines ABIs supported by libffi.
- closure
closure - Create function pointers backed by Rust closures or callbacks.
- errors
- Error types for the
fifficrate. - function
- Functionality to call external FFI functions when the function signature is not necessarily known at compile time.
- types
- Types and traits used to describe types for function signatures for use with libffi.
Macros§
Structs§
- FnPtr
- A untyped function pointer used by fiffi’s function and closure APIs.