1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
#![no_std] #[doc(hidden)] pub use core as _core; /// Creates one or more types capable of representing opaque structs /// in FFI situations. /// /// The resulting type: /// * cannot be constructed outside of the module it is defined in /// * ensures proper pointer alignment /// * is `!Send`, `!Sync`, `!Unpin` /// * is FFI safe /// /// ## Example /// /// Given the following C headers: /// /// ```c /// typedef struct leveldb_options_t leveldb_options_t; /// /// leveldb_options_t* leveldb_options_create(); /// ``` /// /// We can represent the opaque struct `leveldb_options_t` on the Rust /// side like this: /// /// ```rust /// use ffi_opaque::opaque; /// /// opaque! { /// /// And we can document the type. /// pub struct leveldb_options_t; /// } /// /// extern "C" { /// pub fn leveldb_options_create() -> *mut leveldb_options_t; /// } /// ``` /// /// ## Example 2 /// /// Multiple definitions are possible: /// /// ```rust /// use ffi_opaque::opaque; /// /// opaque! { /// /// Documentation for type_1; /// pub struct type_1; /// /// Documentation for type_2; /// pub struct type_2; /// } /// ``` #[macro_export] macro_rules! opaque { ($( $(#[$meta:meta])* $vis:vis struct $name:ident; )+) => {$( $(#[$meta])* #[repr(C)] $vis struct $name { // Required for FFI-safe 0-sized type. // // In the future, this should refer to an extern type. // See https://github.com/rust-lang/rust/issues/43467. _data: [u8; 0], // Required for !Send & !Sync & !Unpin. // // - `*mut u8` is !Send & !Sync. It must be in `PhantomData` to not // affect alignment. // // - `PhantomPinned` is !Unpin. It must be in `PhantomData` because // its memory representation is not considered FFI-safe. _marker: $crate::_core::marker::PhantomData<(*mut u8, $crate::_core::marker::PhantomPinned)>, } )+}; } #[cfg(test)] pub mod test { opaque! { pub struct test_t; } static_assertions::assert_not_impl_any!(test_t: Send, Sync, Unpin); static_assertions::assert_eq_size!(test_t, [u8; 0]); static_assertions::assert_eq_align!(test_t, [u8; 0]); #[deny(improper_ctypes, warnings)] extern "C" { pub fn f(_: *const test_t); } }