A macro generating correct opaque types.
Until RFC 1861 (Extern types) is implemented, representing opaque structs in Rust is hard, as decribed in the corresponding Nomicon section.
Yet, opaque structs are a common pattern, especially when working with C codebases through FFI.
ffi-opaque
provides the opaque!
macro which properly generates such types without having to think about the details.
Types generated by this macro:
- cannot be constructed outside of the module they are defined in
- ensure proper pointer alignment
- are
!Send
,!Sync
,!Unpin
- are FFI safe
In short, they match the behaviour of extern types, as currently implemented in rustc, as closely as possible.
Current differences:
- The generated types have a size of 0 (instead of being unsized)
- The generated types have an alignment of 1 (instead of being usized)
size_of_val
andalign_of_val
can be called on them
Consider this example from the leveldb
C API:
typedef struct leveldb_options_t leveldb_options_t;
typedef struct leveldb_writeoptions_t leveldb_writeoptions_t;
leveldb_options_t* leveldb_options_create();
leveldb_writeoptions_t* leveldb_writeoptions_create();
It uses an opaque struct to avoid leaking structural details of its database options to a library linking to it. We can represent the opaque structs on the Rust side like this:
use ffi_opaque::opaque;
opaque! {
/// Documentation works!
pub struct leveldb_options_t;
/// Options used when writing data
pub struct leveldb_writeoptions_t;
}
extern "C" {
pub fn leveldb_options_create() -> *mut leveldb_options_t;
pub fn leveldb_writeoptions_create() -> *mut leveldb_writeoptions_t;
}
If extern
types become stabilised, this macro may adopt them.
MIT, see LICENSE file.
- David Tolnay (@dtolnay) for raising awareness of many subtle issues
- Nikolai Vasquez (@nvzqz) for implementing the final type and a number of checks