ffi_support/macros.rs
1/* Copyright 2018-2019 Mozilla Foundation
2 *
3 * Licensed under the Apache License (Version 2.0), or the MIT license,
4 * (the "Licenses") at your option. You may not use this file except in
5 * compliance with one of the Licenses. You may obtain copies of the
6 * Licenses at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 * http://opensource.org/licenses/MIT
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the Licenses is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the Licenses for the specific language governing permissions and
15 * limitations under the Licenses. */
16
17/// Implements [`IntoFfi`][crate::IntoFfi] for the provided types (more than one
18/// may be passed in) by allocating `$T` on the heap as an opaque pointer.
19///
20/// This is typically going to be used from the "Rust component", and not the
21/// "FFI component" (see the top level crate documentation for more
22/// information), however you will still need to implement a destructor in the
23/// FFI component using [`define_box_destructor!`][crate::define_box_destructor].
24///
25/// In general, is only safe to do for `send` types (even this is dodgy, but
26/// it's often necessary to keep the locking on the other side of the FFI, so
27/// Sync is too harsh), so we enforce this in this macro. (You're still free to
28/// implement this manually, if this restriction is too harsh for your use case
29/// and you're certain you know what you're doing).
30#[macro_export]
31macro_rules! implement_into_ffi_by_pointer {
32 ($($T:ty),* $(,)*) => {$(
33 unsafe impl $crate::IntoFfi for $T where $T: Send {
34 type Value = *mut $T;
35
36 #[inline]
37 fn ffi_default() -> *mut $T {
38 std::ptr::null_mut()
39 }
40
41 #[inline]
42 fn into_ffi_value(self) -> *mut $T {
43 Box::into_raw(Box::new(self))
44 }
45 }
46 )*}
47}
48
49/// Implements [`IntoFfi`][crate::IntoFfi] for the provided types (more than one
50/// may be passed in) by converting to the type to a JSON string.
51///
52/// Additionally, most of the time we recomment using this crate's protobuf
53/// support, instead of JSON.
54///
55/// This is typically going to be used from the "Rust component", and not the
56/// "FFI component" (see the top level crate documentation for more
57/// information).
58///
59/// Note: Each type passed in must implement or derive `serde::Serialize`.
60///
61/// Note: for this to works, the crate it's called in must depend on `serde` and
62/// `serde_json`.
63///
64/// ## Panics
65///
66/// The [`IntoFfi`][crate::IntoFfi] implementation this macro generates may
67/// panic in the following cases:
68///
69/// - You've passed a type that contains a Map that has non-string keys (which
70/// can't be represented in JSON).
71///
72/// - You've passed a type which has a custom serializer, and the custom
73/// serializer failed.
74///
75/// These cases are both rare enough that this still seems fine for the majority
76/// of uses.
77#[macro_export]
78macro_rules! implement_into_ffi_by_json {
79 ($($T:ty),* $(,)*) => {$(
80 unsafe impl $crate::IntoFfi for $T where $T: serde::Serialize {
81 type Value = *mut std::os::raw::c_char;
82 #[inline]
83 fn ffi_default() -> *mut std::os::raw::c_char {
84 std::ptr::null_mut()
85 }
86 #[inline]
87 fn into_ffi_value(self) -> *mut std::os::raw::c_char {
88 // This panic is inside our catch_panic, so it should be fine.
89 // We've also documented the case where the IntoFfi impl that
90 // calls this panics, and it's rare enough that it shouldn't
91 // matter that if it happens we return an ExternError
92 // representing a panic instead of one of some other type
93 // (especially given that the application isn't likely to be
94 // able to meaningfully handle JSON serialization failure).
95 let as_string = serde_json::to_string(&self).unwrap();
96 $crate::rust_string_to_c(as_string)
97 }
98 }
99 )*}
100}
101
102/// Implements [`IntoFfi`][crate::IntoFfi] for the provided types (more than one
103/// may be passed in) implementing `prost::Message` (protobuf auto-generated
104/// type) by converting to the type to a [`ByteBuffer`][crate::ByteBuffer]. This
105/// [`ByteBuffer`][crate::ByteBuffer] should later be passed by value.
106///
107/// Note: for this to works, the crate it's called in must depend on `prost`.
108///
109/// Note: Each type passed in must implement or derive `prost::Message`.
110#[macro_export]
111macro_rules! implement_into_ffi_by_protobuf {
112 ($($FFIType:ty),* $(,)*) => {$(
113 unsafe impl $crate::IntoFfi for $FFIType where $FFIType: prost::Message {
114 type Value = $crate::ByteBuffer;
115 #[inline]
116 fn ffi_default() -> Self::Value {
117 Default::default()
118 }
119
120 #[inline]
121 fn into_ffi_value(self) -> Self::Value {
122 use prost::Message;
123 let mut bytes = Vec::with_capacity(self.encoded_len());
124 // Unwrap is safe, since we have reserved sufficient capacity in
125 // the vector.
126 self.encode(&mut bytes).unwrap();
127 bytes.into()
128 }
129 }
130 )*}
131}
132
133/// Implement [`InfoFfi`][crate::IntoFfi] for a type by converting through
134/// another type.
135///
136/// The argument `$MidTy` argument must implement `From<$SrcTy>` and
137/// [`InfoFfi`][crate::IntoFfi].
138///
139/// This is provided (even though it's trivial) because it is always safe (well,
140/// so long as `$MidTy`'s [`IntoFfi`][crate::IntoFfi] implementation is
141/// correct), but would otherwise require use of `unsafe` to implement.
142#[macro_export]
143macro_rules! implement_into_ffi_by_delegation {
144 ($SrcTy:ty, $MidTy:ty) => {
145 unsafe impl $crate::IntoFfi for $SrcTy
146 where
147 $MidTy: From<$SrcTy> + $crate::IntoFfi,
148 {
149 // The <$MidTy as SomeTrait>::method is required even when it would
150 // be ambiguous due to some obscure details of macro syntax.
151 type Value = <$MidTy as $crate::IntoFfi>::Value;
152
153 #[inline]
154 fn ffi_default() -> Self::Value {
155 <$MidTy as $crate::IntoFfi>::ffi_default()
156 }
157
158 #[inline]
159 fn into_ffi_value(self) -> Self::Value {
160 use $crate::IntoFfi;
161 <$MidTy as From<$SrcTy>>::from(self).into_ffi_value()
162 }
163 }
164 };
165}
166
167/// For a number of reasons (name collisions are a big one, but, it also wouldn't work on all
168/// platforms), we cannot export `extern "C"` functions from this library. However, it's pretty
169/// common to want to free strings allocated by rust, so many libraries will need this, so we
170/// provide it as a macro.
171///
172/// It simply expands to a `#[no_mangle] pub unsafe extern "C" fn` which wraps this crate's
173/// [`destroy_c_string`][crate::destroy_c_string] function.
174///
175/// ## Caveats
176///
177/// If you're using multiple separately compiled rust libraries in your application, it's critical
178/// that you are careful to only ever free strings allocated by a Rust library using the same rust
179/// library. Passing them to a different Rust library's string destructor will cause you to corrupt
180/// multiple heaps.
181///
182/// Additionally, be sure that all strings you pass to this were actually allocated by rust. It's a
183/// common issue for JNA code to transparently convert Pointers to things to Strings behind the
184/// scenes, which is quite risky here. (To avoid this in JNA, only use `String` for passing
185/// read-only strings into Rust, e.g. it's for passing `*const c_char`. All other uses should use
186/// `Pointer` and `getString()`).
187///
188/// Finally, to avoid name collisions, it is strongly recommended that you provide an name for this
189/// function unique to your library.
190///
191/// ## Example
192///
193/// ```rust
194/// # use ffi_support::define_string_destructor;
195/// define_string_destructor!(mylib_destroy_string);
196/// ```
197#[macro_export]
198macro_rules! define_string_destructor {
199 ($mylib_destroy_string:ident) => {
200 /// Public destructor for strings managed by the other side of the FFI.
201 ///
202 /// # Safety
203 ///
204 /// This will free the string pointer it gets passed in as an argument,
205 /// and thus can be wildly unsafe if misused.
206 ///
207 /// See the documentation of `ffi_support::destroy_c_string` and
208 /// `ffi_support::define_string_destructor!` for further info.
209 #[no_mangle]
210 pub unsafe extern "C" fn $mylib_destroy_string(s: *mut std::os::raw::c_char) {
211 // Note: This should never happen, but in the case of a bug aborting
212 // here is better than the badness that happens if we unwind across
213 // the FFI boundary.
214 $crate::abort_on_panic::with_abort_on_panic(|| {
215 if !s.is_null() {
216 $crate::destroy_c_string(s)
217 }
218 });
219 }
220 };
221}
222
223/// Define a (public) destructor for a type that was allocated by
224/// `Box::into_raw(Box::new(value))` (e.g. a pointer which is probably opaque).
225///
226/// ## Caveats
227///
228/// When called over the FFI, this can go wrong in a ridiculous number of ways,
229/// and we can't really prevent any of them. But essentially, the caller (on the
230/// other side of the FFI) needs to be extremely careful to ensure that it stops
231/// using the pointer after it's freed.
232///
233/// Also, to avoid name collisions, it is strongly recommended that you provide
234/// an name for this function unique to your library. (This is true for all
235/// functions you expose).
236///
237/// However, when called from rust, this is safe, as it becomes a function that
238/// just drops a `Option<Box<T>>` with some panic handling.
239///
240/// ## Example
241///
242/// ```rust
243/// # use ffi_support::define_box_destructor;
244/// struct CoolType(Vec<i32>);
245///
246/// define_box_destructor!(CoolType, mylib_destroy_cooltype);
247/// ```
248#[macro_export]
249macro_rules! define_box_destructor {
250 ($T:ty, $destructor_name:ident) => {
251 /// # Safety
252 /// This is equivalent to calling Box::from_raw with panic handling, and
253 /// thus inherits [`Box::from_raw`]'s safety properties. That is to say,
254 /// this function is wildly unsafe.
255 #[no_mangle]
256 pub unsafe extern "C" fn $destructor_name(v: *mut $T) {
257 // We should consider passing an error parameter in here rather than
258 // aborting, but at the moment the only case where we do this
259 // (interrupt handles) should never panic in Drop, so it's probably
260 // fine.
261 $crate::abort_on_panic::with_abort_on_panic(|| {
262 if !v.is_null() {
263 drop(Box::from_raw(v))
264 }
265 });
266 }
267 };
268}
269
270/// Define a (public) destructor for the [`ByteBuffer`][crate::ByteBuffer] type.
271///
272/// ## Caveats
273///
274/// If you're using multiple separately compiled rust libraries in your application, it's critical
275/// that you are careful to only ever free `ByteBuffer` instances allocated by a Rust library using
276/// the same rust library. Passing them to a different Rust library's string destructor will cause
277/// you to corrupt multiple heaps.
278/// One common ByteBuffer destructor is defined per Rust library.
279///
280/// Also, to avoid name collisions, it is strongly recommended that you provide an name for this
281/// function unique to your library. (This is true for all functions you expose).
282///
283/// ## Example
284///
285/// ```rust
286/// # use ffi_support::define_bytebuffer_destructor;
287/// define_bytebuffer_destructor!(mylib_destroy_bytebuffer);
288/// ```
289#[macro_export]
290macro_rules! define_bytebuffer_destructor {
291 ($destructor_name:ident) => {
292 #[no_mangle]
293 pub extern "C" fn $destructor_name(v: $crate::ByteBuffer) {
294 // Note: This should never happen, but in the case of a bug aborting
295 // here is better than the badness that happens if we unwind across
296 // the FFI boundary.
297 $crate::abort_on_panic::with_abort_on_panic(|| v.destroy())
298 }
299 };
300}
301
302/// Define a (public) destructor for a type that lives inside a lazy_static
303/// [`ConcurrentHandleMap`][crate::ConcurrentHandleMap].
304///
305/// Note that this is actually totally safe, unlike the other
306/// `define_blah_destructor` macros.
307///
308/// A critical difference, however, is that this dtor takes an `err` out
309/// parameter to indicate failure. This difference is why the name is different
310/// as well (deleter vs destructor).
311///
312/// ## Example
313///
314/// ```rust
315/// # use lazy_static::lazy_static;
316/// # use ffi_support::{ConcurrentHandleMap, define_handle_map_deleter};
317/// struct Thing(Vec<i32>);
318/// // Somewhere...
319/// lazy_static! {
320/// static ref THING_HANDLES: ConcurrentHandleMap<Thing> = ConcurrentHandleMap::new();
321/// }
322/// define_handle_map_deleter!(THING_HANDLES, mylib_destroy_thing);
323/// ```
324#[macro_export]
325macro_rules! define_handle_map_deleter {
326 ($HANDLE_MAP_NAME:ident, $destructor_name:ident) => {
327 #[no_mangle]
328 pub extern "C" fn $destructor_name(v: u64, err: &mut $crate::ExternError) {
329 $crate::call_with_result(err, || {
330 // Force type errors here.
331 let map: &$crate::ConcurrentHandleMap<_> = &*$HANDLE_MAP_NAME;
332 map.delete_u64(v)
333 })
334 }
335 };
336}
337
338/// Force a compile error if the condition is not met. Requires a unique name
339/// for the assertion for... reasons. This is included mainly because it's a
340/// common desire for FFI code, but not for other sorts of code.
341///
342/// # Examples
343///
344/// Failing example:
345///
346/// ```compile_fail
347/// ffi_support::static_assert!(THIS_SHOULD_FAIL, false);
348/// ```
349///
350/// Passing example:
351///
352/// ```
353/// ffi_support::static_assert!(THIS_SHOULD_PASS, true);
354/// ```
355#[macro_export]
356macro_rules! static_assert {
357 ($ASSERT_NAME:ident, $test:expr) => {
358 #[allow(dead_code, nonstandard_style)]
359 const $ASSERT_NAME: [u8; 0 - (!$test as bool as usize)] =
360 [0u8; 0 - (!$test as bool as usize)];
361 };
362}