#macro #safety #behavior

ffi-opaque

A simple macro to create correct opaque pointers

4 releases (stable)

2.0.1 Mar 31, 2021
2.0.0 Dec 17, 2020
1.0.0 Dec 16, 2020
0.1.0 Dec 11, 2020

#88 in FFI

Download history 9076/week @ 2024-02-29 9866/week @ 2024-03-07 9346/week @ 2024-03-14 9358/week @ 2024-03-21 7997/week @ 2024-03-28 9448/week @ 2024-04-04 9512/week @ 2024-04-11 8386/week @ 2024-04-18 8622/week @ 2024-04-25 10030/week @ 2024-05-02 11765/week @ 2024-05-09 8734/week @ 2024-05-16 9437/week @ 2024-05-23 9860/week @ 2024-05-30 8623/week @ 2024-06-06 8684/week @ 2024-06-13

38,490 downloads per month
Used in 36 crates (5 directly)

MIT license

7KB

ffi-opaque

A macro generating correct opaque types.

What it does

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 and align_of_val can be called on them

Usage example

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;
}

Possible future extensions

If extern types become stabilised, this macro may adopt them.

License

MIT, see LICENSE file.

Acklowledgements

No runtime deps