CO3
Given correct declarations, safely export and/or import FFI bindings:
-
Native-Rust ergonomics
- ergonomics of APIs and generated wrappers are idiomatic to Rust users.
- FFI boundary mechanics are zero-cost abstracted yet remain configurable.
- Except for statics, export declarations can also be used for imports.
-
Soundness-first FFI interoperability
- soundness is never weakened for the sake of performance or memory footprint in the default configuration.
- if preserving soundness requires additional validation, temporary storage, or cloning, that cost is accepted.
- only explicit opt-in modes prioritize performance by explicitly shifting soundness responsibility to the user.
Why Bother?
Ain't nobody got time for this, just give me a tldr. Ok, but don't take the following claims as a form of hubris:
-
You won't find anything remotely as useful, safe or as expressive as
CO3- which crate allows using native Rust types? the ones claiming so still require wrappers
- while many claim expressivity, have you ever seen a runtime tagged-dispatch in Rust?
-
If you're exporting FFI from a Rust crate,
CO3is, by far, the easiest way to do soCO3aims to make the complex process of FFI generation completely painless- literally, just write down the export declarations as if writing native
Rust
-
Although recent on the market,
CO3is already incredibly feature rich and well tested- the initial release of
CO3required it reached feature parity with the ecosystem - which crate allows you to use generics in FFI or custom DSTs? yes,
CO3does
- the initial release of
Check the release article for the motivation behind CO3 and in-depth analysis of its features.
ABI Stability
Although this crate is pre-1.0.0, its ABI is considered stable. This does not mean the API is stable. In practice:
- ABI stability means FFI contracts (symbol names, calling conventions, and data layout expectations) are intended to remain compatible across updates.
- API instability means Rust-facing items (fns, trait shapes, modules, and type signatures) may still change and require source updates when upgrading.
In other words, external binaries that integrate through the defined ABI should keep working, while Rust code using this crate directly may need refactoring between releases.
Example
Using CO3 is super-duper simple yet highly expressive. In a nutshell:
- mark Rust types that cross the boundary with
#[derive(ReprC)] - describe the boundary API with
ffi!(fns, impls and types)
use ;
ffi!
Note that type deriving ReprC, although recommended, is not required to have a stable representation.
Tagged Dispatch
It is common in FFI for several concrete types to share one C representation. Think of FFI functions
like SQLAllocHandle
which works for different tag types
or SQLSetEnvAttr
where an attribute's concrete type determines the accepted value representation.
use ;
;
;
ffi!
To see what CO3 is capable of and what using it looks like in practice, check out rs-odbc.
Related Projects
cxx
This crate generates a C++ API and bridge code, with compile-time checks for supported declarations against C++ headers.
If your FFI is Rust <-> C++, using this crate is preferable because it gives deep cross-language integration. As always, considering the author, this is a very well made crate. I think both crates could learn from each other.
bindgen
This crate generates Rust bindings from C headers.
I maintain this is not a crate you would ever want to use because C APIs communicate many invariants through informal ways that automated translation into Rust bindings cannot capture.
Because Rust's type system is much more expressive than C's, it's much better to write an authoritative layer in Rust.
cbindgen
Use this crate to build C headers from CO3 export declarations.
cheadergen
The same as cbindgen but newer. I'd prefer it if it were at the same feature parity level.
safer_ffi
While I appreciate the work done, this crate looks more like an attempt than a real solution.
Given the existence of CO3, I fail to see why would anyone recommend using this crate. The API is too complicated while expressivity just isn't there.
If there is anything found missing in CO3 that safer-ffi can do, report it and the gap should be closed immediately.
Diplomat
Generates not only C API glue for your Rust exports but also bindings for supported target languages.
I don't think CO3 would aim to match that functionality, but I do think they'd benefit a lot from building on top of CO3.
Interoptopus
Quite similar to Diplomat in scope.
Likewise, I believe this crate could build on top of CO3.