Introduction
ezffi is a procedural-macro crate that turns ordinary Rust types and functions into C-FFI bindings, without any boilerplate and with a focus on performance, keeping 0% overhead though the FFI layer when theoretically possible.
A small taste:
#![allow(unused)] fn main() { #[ezffi::export] pub struct Point { pub x: f64, pub y: f64 } #[ezffi::export] impl Point { pub fn new(x: f64, y: f64) -> Self { Self { x, y } } pub fn distance(&self, other: &Point) -> f64 { ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt() } } }
produces, on the C side:
typedef struct MyCratePoint { double x; double y; } MyCratePoint;
MyCratePoint my_crate_point_new(double x, double y);
double my_crate_point_distance(const MyCratePoint *this_, const MyCratePoint *other);
That's the visible surface. Underneath, ezffi is solving a handful of problems:
- Layout decisions — which Rust types can cross as
#[repr(C)]and which need an opaque pointer wrapper. - Async —
ezffiallows you to export async functions and exposes logic to define the async dispatcher of your choice. - Ownership —
Box-ed types go behind their generated FFI struct, with a matching_freefunction so C can drop them. - Rust std types — Rust
Option<T>,Result<T, E>,Vec<T>,Arc<T>,Rc<T>,HashMap<K, V>,String, etc. are types that you can use in your exported functions without having to worry about implementation details. - Cross-crate — a library can export its types and functions so Rust, C, Swift and any other language can consume them. You can also write your own library using
ezffion top of that library and use those types in your exported functions without any extra configuration.
This library has a heavy focus un areas like HPC and Scientific software, where comunicating Rust with other languages so performance is really important for me and archiving 0% performance overhead is one of my goals (thought it may be immposible in some sceneraios). Check the benchmarks chapter for more informacion on how the bench are organized and executed and check BENCH_RESULTS.md on the root of the repo to see in witch sncenarios you can get that 0% overhead and in which ones you have to pay for the FFI layer, so you can make the right choice for your project.
Disclaimer: this library is in the early stages of development. It contains all the features I personally need for my own projects and professional work, and that can change (I'll try not to). Feel free to use it and contribute if you'd like to get features in or fix issues you're hitting. The base I've been working on is solid and lets me keep building on top of it. Hope you like it and that it helps the community write better and safer code, taking advantage of Rust's features.