/* Copyright 2018-2019 Mozilla Foundation * * Licensed under the Apache License (Version 2.0), or the MIT license, * (the "Licenses") at your option. You may not use this file except in * compliance with one of the Licenses. You may obtain copies of the * Licenses at: * * http://www.apache.org/licenses/LICENSE-2.0 * http://opensource.org/licenses/MIT * * Unless required by applicable law or agreed to in writing, software * distributed under the Licenses is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licenses for the specific language governing permissions and * limitations under the Licenses. */ /// Implements [`IntoFfi`][crate::IntoFfi] for the provided types (more than one /// may be passed in) by allocating `$T` on the heap as an opaque pointer. /// /// This is typically going to be used from the "Rust component", and not the /// "FFI component" (see the top level crate documentation for more /// information), however you will still need to implement a destructor in the /// FFI component using [`define_box_destructor!`][crate::define_box_destructor]. /// /// In general, is only safe to do for `send` types (even this is dodgy, but /// it's often necessary to keep the locking on the other side of the FFI, so /// Sync is too harsh), so we enforce this in this macro. (You're still free to /// implement this manually, if this restriction is too harsh for your use case /// and you're certain you know what you're doing). #[macro_export] macro_rules! implement_into_ffi_by_pointer { ($($T:ty),* $(,)*) => {$( unsafe impl $crate::IntoFfi for $T where $T: Send { type Value = *mut $T; #[inline] fn ffi_default() -> *mut $T { std::ptr::null_mut() } #[inline] fn into_ffi_value(self) -> *mut $T { Box::into_raw(Box::new(self)) } } )*} } /// Implements [`IntoFfi`][crate::IntoFfi] for the provided types (more than one /// may be passed in) by converting to the type to a JSON string. /// /// Additionally, most of the time we recomment using this crate's protobuf /// support, instead of JSON. /// /// This is typically going to be used from the "Rust component", and not the /// "FFI component" (see the top level crate documentation for more /// information). /// /// Note: Each type passed in must implement or derive `serde::Serialize`. /// /// Note: for this to works, the crate it's called in must depend on `serde` and /// `serde_json`. /// /// ## Panics /// /// The [`IntoFfi`][crate::IntoFfi] implementation this macro generates may /// panic in the following cases: /// /// - You've passed a type that contains a Map that has non-string keys (which /// can't be represented in JSON). /// /// - You've passed a type which has a custom serializer, and the custom /// serializer failed. /// /// These cases are both rare enough that this still seems fine for the majority /// of uses. #[macro_export] macro_rules! implement_into_ffi_by_json { ($($T:ty),* $(,)*) => {$( unsafe impl $crate::IntoFfi for $T where $T: serde::Serialize { type Value = *mut std::os::raw::c_char; #[inline] fn ffi_default() -> *mut std::os::raw::c_char { std::ptr::null_mut() } #[inline] fn into_ffi_value(self) -> *mut std::os::raw::c_char { // This panic is inside our catch_panic, so it should be fine. // We've also documented the case where the IntoFfi impl that // calls this panics, and it's rare enough that it shouldn't // matter that if it happens we return an ExternError // representing a panic instead of one of some other type // (especially given that the application isn't likely to be // able to meaningfully handle JSON serialization failure). let as_string = serde_json::to_string(&self).unwrap(); $crate::rust_string_to_c(as_string) } } )*} } /// Implements [`IntoFfi`][crate::IntoFfi] for the provided types (more than one /// may be passed in) implementing `prost::Message` (protobuf auto-generated /// type) by converting to the type to a [`ByteBuffer`][crate::ByteBuffer]. This /// [`ByteBuffer`][crate::ByteBuffer] should later be passed by value. /// /// Note: for this to works, the crate it's called in must depend on `prost`. /// /// Note: Each type passed in must implement or derive `prost::Message`. #[macro_export] macro_rules! implement_into_ffi_by_protobuf { ($($FFIType:ty),* $(,)*) => {$( unsafe impl $crate::IntoFfi for $FFIType where $FFIType: prost::Message { type Value = $crate::ByteBuffer; #[inline] fn ffi_default() -> Self::Value { Default::default() } #[inline] fn into_ffi_value(self) -> Self::Value { use prost::Message; let mut bytes = Vec::with_capacity(self.encoded_len()); // Unwrap is safe, since we have reserved sufficient capacity in // the vector. self.encode(&mut bytes).unwrap(); bytes.into() } } )*} } /// Implement [`InfoFfi`][crate::IntoFfi] for a type by converting through /// another type. /// /// The argument `$MidTy` argument must implement `From<$SrcTy>` and /// [`InfoFfi`][crate::IntoFfi]. /// /// This is provided (even though it's trivial) because it is always safe (well, /// so long as `$MidTy`'s [`IntoFfi`][crate::IntoFfi] implementation is /// correct), but would otherwise require use of `unsafe` to implement. #[macro_export] macro_rules! implement_into_ffi_by_delegation { ($SrcTy:ty, $MidTy:ty) => { unsafe impl $crate::IntoFfi for $SrcTy where $MidTy: From<$SrcTy> + $crate::IntoFfi, { // The <$MidTy as SomeTrait>::method is required even when it would // be ambiguous due to some obscure details of macro syntax. type Value = <$MidTy as $crate::IntoFfi>::Value; #[inline] fn ffi_default() -> Self::Value { <$MidTy as $crate::IntoFfi>::ffi_default() } #[inline] fn into_ffi_value(self) -> Self::Value { use $crate::IntoFfi; <$MidTy as From<$SrcTy>>::from(self).into_ffi_value() } } }; } /// For a number of reasons (name collisions are a big one, but, it also wouldn't work on all /// platforms), we cannot export `extern "C"` functions from this library. However, it's pretty /// common to want to free strings allocated by rust, so many libraries will need this, so we /// provide it as a macro. /// /// It simply expands to a `#[no_mangle] pub unsafe extern "C" fn` which wraps this crate's /// [`destroy_c_string`][crate::destroy_c_string] function. /// /// ## Caveats /// /// If you're using multiple separately compiled rust libraries in your application, it's critical /// that you are careful to only ever free strings allocated by a Rust library using the same rust /// library. Passing them to a different Rust library's string destructor will cause you to corrupt /// multiple heaps. /// /// Additionally, be sure that all strings you pass to this were actually allocated by rust. It's a /// common issue for JNA code to transparently convert Pointers to things to Strings behind the /// scenes, which is quite risky here. (To avoid this in JNA, only use `String` for passing /// read-only strings into Rust, e.g. it's for passing `*const c_char`. All other uses should use /// `Pointer` and `getString()`). /// /// Finally, to avoid name collisions, it is strongly recommended that you provide an name for this /// function unique to your library. /// /// ## Example /// /// ```rust /// # use ffi_support::define_string_destructor; /// define_string_destructor!(mylib_destroy_string); /// ``` #[macro_export] macro_rules! define_string_destructor { ($mylib_destroy_string:ident) => { /// Public destructor for strings managed by the other side of the FFI. /// /// # Safety /// /// This will free the string pointer it gets passed in as an argument, /// and thus can be wildly unsafe if misused. /// /// See the documentation of `ffi_support::destroy_c_string` and /// `ffi_support::define_string_destructor!` for further info. #[no_mangle] pub unsafe extern "C" fn $mylib_destroy_string(s: *mut std::os::raw::c_char) { // Note: This should never happen, but in the case of a bug aborting // here is better than the badness that happens if we unwind across // the FFI boundary. $crate::abort_on_panic::with_abort_on_panic(|| { if !s.is_null() { $crate::destroy_c_string(s) } }); } }; } /// Define a (public) destructor for a type that was allocated by /// `Box::into_raw(Box::new(value))` (e.g. a pointer which is probably opaque). /// /// ## Caveats /// /// When called over the FFI, this can go wrong in a ridiculous number of ways, /// and we can't really prevent any of them. But essentially, the caller (on the /// other side of the FFI) needs to be extremely careful to ensure that it stops /// using the pointer after it's freed. /// /// Also, to avoid name collisions, it is strongly recommended that you provide /// an name for this function unique to your library. (This is true for all /// functions you expose). /// /// However, when called from rust, this is safe, as it becomes a function that /// just drops a `Option>` with some panic handling. /// /// ## Example /// /// ```rust /// # use ffi_support::define_box_destructor; /// struct CoolType(Vec); /// /// define_box_destructor!(CoolType, mylib_destroy_cooltype); /// ``` #[macro_export] macro_rules! define_box_destructor { ($T:ty, $destructor_name:ident) => { /// # Safety /// This is equivalent to calling Box::from_raw with panic handling, and /// thus inherits [`Box::from_raw`]'s safety properties. That is to say, /// this function is wildly unsafe. #[no_mangle] pub unsafe extern "C" fn $destructor_name(v: *mut $T) { // We should consider passing an error parameter in here rather than // aborting, but at the moment the only case where we do this // (interrupt handles) should never panic in Drop, so it's probably // fine. $crate::abort_on_panic::with_abort_on_panic(|| { if !v.is_null() { drop(Box::from_raw(v)) } }); } }; } /// Define a (public) destructor for the [`ByteBuffer`][crate::ByteBuffer] type. /// /// ## Caveats /// /// If you're using multiple separately compiled rust libraries in your application, it's critical /// that you are careful to only ever free `ByteBuffer` instances allocated by a Rust library using /// the same rust library. Passing them to a different Rust library's string destructor will cause /// you to corrupt multiple heaps. /// One common ByteBuffer destructor is defined per Rust library. /// /// Also, to avoid name collisions, it is strongly recommended that you provide an name for this /// function unique to your library. (This is true for all functions you expose). /// /// ## Example /// /// ```rust /// # use ffi_support::define_bytebuffer_destructor; /// define_bytebuffer_destructor!(mylib_destroy_bytebuffer); /// ``` #[macro_export] macro_rules! define_bytebuffer_destructor { ($destructor_name:ident) => { #[no_mangle] pub extern "C" fn $destructor_name(v: $crate::ByteBuffer) { // Note: This should never happen, but in the case of a bug aborting // here is better than the badness that happens if we unwind across // the FFI boundary. $crate::abort_on_panic::with_abort_on_panic(|| v.destroy()) } }; } /// Define a (public) destructor for a type that lives inside a lazy_static /// [`ConcurrentHandleMap`][crate::ConcurrentHandleMap]. /// /// Note that this is actually totally safe, unlike the other /// `define_blah_destructor` macros. /// /// A critical difference, however, is that this dtor takes an `err` out /// parameter to indicate failure. This difference is why the name is different /// as well (deleter vs destructor). /// /// ## Example /// /// ```rust /// # use lazy_static::lazy_static; /// # use ffi_support::{ConcurrentHandleMap, define_handle_map_deleter}; /// struct Thing(Vec); /// // Somewhere... /// lazy_static! { /// static ref THING_HANDLES: ConcurrentHandleMap = ConcurrentHandleMap::new(); /// } /// define_handle_map_deleter!(THING_HANDLES, mylib_destroy_thing); /// ``` #[macro_export] macro_rules! define_handle_map_deleter { ($HANDLE_MAP_NAME:ident, $destructor_name:ident) => { #[no_mangle] pub extern "C" fn $destructor_name(v: u64, err: &mut $crate::ExternError) { $crate::call_with_result(err, || { // Force type errors here. let map: &$crate::ConcurrentHandleMap<_> = &*$HANDLE_MAP_NAME; map.delete_u64(v) }) } }; } /// Force a compile error if the condition is not met. Requires a unique name /// for the assertion for... reasons. This is included mainly because it's a /// common desire for FFI code, but not for other sorts of code. /// /// # Examples /// /// Failing example: /// /// ```compile_fail /// ffi_support::static_assert!(THIS_SHOULD_FAIL, false); /// ``` /// /// Passing example: /// /// ``` /// ffi_support::static_assert!(THIS_SHOULD_PASS, true); /// ``` #[macro_export] macro_rules! static_assert { ($ASSERT_NAME:ident, $test:expr) => { #[allow(dead_code, nonstandard_style)] const $ASSERT_NAME: [u8; 0 - (!$test as bool as usize)] = [0u8; 0 - (!$test as bool as usize)]; }; }