ffi_support/
into_ffi.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
17use crate::string::*;
18use std::os::raw::{c_char, c_void};
19use std::ptr;
20
21/// This trait is used to return types over the FFI. It essentially is a mapping between a type and
22/// version of that type we can pass back to C (`IntoFfi::Value`).
23///
24/// The main wrinkle is that we need to be able to pass a value back to C in both the success and
25/// error cases. In the error cases, we don't want there to need to be any cleanup for the foreign
26/// code to do, and we want the API to be relatively easy to use.
27///
28/// Additionally, the mapping is not consistent for different types. For some rust types, we want to
29/// convert them to JSON. For some, we want to return an opaque `*mut T` handle. For others,
30/// we'd like to return by value.
31///
32/// This trait supports those cases by adding some type-level indirection, and allowing both cases
33/// to be provided (both cases what is done in the error and success cases).
34///
35/// We implement this for the following types:
36///
37/// - `String`, by conversion to `*mut c_char`. Note that the caller (on the other side of the FFI)
38///   is expected to free this, so you will need to provide them with a destructor for strings,
39///   which can be done with the [`define_string_destructor!`] macro.
40///
41/// - `()`: as a no-op conversion -- this just allows us to expose functions without a return type
42///   over the FFI.
43///
44/// - `bool`: is implemented by conversion to `u8` (`0u8` is `false`, `1u8` is `true`, and
45///   `ffi_default()` is `false`). This is because it doesn't seem to be safe to pass over the FFI
46///   directly (or at least, doing so might hit a bug in JNA).
47///
48/// - All numeric primitives except  `isize`, `usize`, `char`, `i128`, and `u128` are implememented
49///   by passing directly through (and using `Default::default()` for `ffi_default()`).
50///     - `isize`, `usize` could be added, but they'd be quite easy to accidentally misuse, so we
51///       currently omit them.
52///     - `char` is less easy to misuse, but it's also less clear why you'd want to be doing this.
53///       If we did ever add this, we'd probably want to convert to a `u32` (similar to how we
54///       convert `bool` to `u8`) for better ABI stability.
55///     - `i128` and `u128` do not have a stable ABI, so they cannot be returned across the FFI.
56///
57/// - `Option<T>` where `T` is `IntoFfi`, by returning `IntoFfi::ffi_default()` for `None`.
58///
59/// None of these are directly helpful for user types though, so macros are provided for the
60/// following cases:
61///
62/// 1. For types which are passed around by an opaque pointer, the macro
63///    [`implement_into_ffi_by_pointer!`] is provided.
64///
65/// 2. For types which should be returned as a JSON string, the macro
66///    [`implement_into_ffi_by_json!`] is provided.
67///
68/// See the "Examples" section below for some other cases, such as returning by value.
69///
70/// ## Safety
71///
72/// This is an unsafe trait (implementing it requires `unsafe impl`). This is because we cannot
73/// guarantee that your type is safe to pass to C. The helpers we've providedĀ as macros should be
74/// safe to use, and in the cases where a common pattern can't be done both safely and generically,
75/// we've opted not to provide a macro for it. That said, many of these cases are still safe if you
76/// meet some relatively basic requirements, see below for examples.
77///
78/// ## Examples
79///
80/// ### Returning types by value
81///
82/// If you want to return a type by value, we don't provide a macro for this, primarially because
83/// doing so cannot be statically guarantee that it is safe. However, it *is* safe for the cases
84/// where the type is either `#[repr(C)]` or `#[repr(transparent)]`. If this doesn't hold, you will
85/// want to use a different option!
86///
87/// Regardless, if this holds, it's fairly simple to implement, for example:
88///
89/// ```rust
90/// # use ffi_support::IntoFfi;
91/// #[derive(Default)]
92/// #[repr(C)]
93/// pub struct Point {
94///     pub x: i32,
95///     pub y: i32,
96/// }
97///
98/// unsafe impl IntoFfi for Point {
99///     type Value = Self;
100///     #[inline] fn ffi_default() -> Self { Default::default() }
101///     #[inline] fn into_ffi_value(self) -> Self { self }
102/// }
103/// ```
104///
105/// ### Conversion to another type (which is returned over the FFI)
106///
107/// In the FxA FFI, we used to have a `SyncKeys` type, which was converted to a different type before
108/// returning over the FFI. (The real FxA FFI is a little different, and more complex, but this is
109/// relatively close, and more widely recommendable than the one the FxA FFI uses):
110///
111/// This is fairly easy to do by performing the conversion inside `IntoFfi`.
112///
113/// ```rust
114/// # use ffi_support::{self, IntoFfi};
115/// # use std::{ptr, os::raw::c_char};
116/// pub struct SyncKeys(pub String, pub String);
117///
118/// #[repr(C)]
119/// pub struct SyncKeysC {
120///     pub sync_key: *mut c_char,
121///     pub xcs: *mut c_char,
122/// }
123///
124/// unsafe impl IntoFfi for SyncKeys {
125///     type Value = SyncKeysC;
126///     #[inline]
127///     fn ffi_default() -> SyncKeysC {
128///         SyncKeysC {
129///             sync_key: ptr::null_mut(),
130///             xcs: ptr::null_mut(),
131///         }
132///     }
133///
134///     #[inline]
135///     fn into_ffi_value(self) -> SyncKeysC {
136///         SyncKeysC {
137///             sync_key: ffi_support::rust_string_to_c(self.0),
138///             xcs:      ffi_support::rust_string_to_c(self.1),
139///         }
140///     }
141/// }
142///
143/// // Note: this type manages memory, so you still will want to expose a destructor for this,
144/// // and possibly implement Drop as well.
145/// ```
146pub unsafe trait IntoFfi: Sized {
147    /// This type must be:
148    ///
149    /// 1. Compatible with C, which is to say `#[repr(C)]`, a numeric primitive,
150    ///    another type that has guarantees made about it's layout, or a
151    ///    `#[repr(transparent)]` wrapper around one of those.
152    ///
153    ///    One could even use `&T`, so long as `T: Sized`, although it's
154    ///    extremely dubious to return a reference to borrowed memory over the
155    ///    FFI, since it's very difficult for the caller to know how long it
156    ///    remains valid.
157    ///
158    /// 2. Capable of storing an empty/ignorable/default value.
159    ///
160    /// 3. Capable of storing the actual value.
161    ///
162    /// Valid examples include:
163    ///
164    /// - Primitive numbers (other than i128/u128)
165    ///
166    /// - #[repr(C)] structs containing only things on this list.
167    ///
168    /// - `Option<Box<T>>`, but only if `T` is `Sized`. (Internally this is
169    ///   guaranteed to be represented equivalently to a pointer)
170    ///
171    /// - Raw pointers such as `*const T`, and `*mut T`, but again, only if `T`
172    ///   is `Sized` (`*const [T]`, `*mut dyn SomeTrait` etc are not valid).
173    ///
174    /// - Enums with a fixed `repr`, although it's a good idea avoid
175    ///   `#[repr(C)]` enums in favor of, say, `#[repr(i32)]` (for example, any
176    ///   fixed type there should be fine), as it's potentially error prone to
177    ///   access `#[repr(C)]` enums from Android over JNA (it's only safe if C's
178    ///   `sizeof(int) == 4`, which is very common, but not universally true).
179    ///
180    /// - `&T`/`&mut T` where `T: Sized` but only if you really know what you're
181    ///   doing, because this is probably a mistake.
182    ///
183    /// Invalid examples include things like `&str`, `&[T]`, `String`, `Vec<T>`,
184    /// `std::ffi::CString`, `&std::ffi::CStr`, etc.
185    type Value;
186
187    /// Return an 'empty' value. This is what's passed back to C in the case of an error,
188    /// so it doesn't actually need to be "empty", so much as "ignorable". Note that this
189    /// is also used when an empty `Option<T>` is returned.
190    fn ffi_default() -> Self::Value;
191
192    /// Convert ourselves into a value we can pass back to C with confidence.
193    fn into_ffi_value(self) -> Self::Value;
194}
195
196unsafe impl IntoFfi for String {
197    type Value = *mut c_char;
198
199    #[inline]
200    fn ffi_default() -> Self::Value {
201        ptr::null_mut()
202    }
203
204    #[inline]
205    fn into_ffi_value(self) -> Self::Value {
206        rust_string_to_c(self)
207    }
208}
209
210// Implement IntoFfi for Option<T> by falling back to ffi_default for None.
211unsafe impl<T: IntoFfi> IntoFfi for Option<T> {
212    type Value = <T as IntoFfi>::Value;
213
214    #[inline]
215    fn ffi_default() -> Self::Value {
216        T::ffi_default()
217    }
218
219    #[inline]
220    fn into_ffi_value(self) -> Self::Value {
221        if let Some(s) = self {
222            s.into_ffi_value()
223        } else {
224            T::ffi_default()
225        }
226    }
227}
228
229// We've had problems in the past returning booleans over the FFI (specifically to JNA), and so
230// we convert them to `u8`.
231unsafe impl IntoFfi for bool {
232    type Value = u8;
233    #[inline]
234    fn ffi_default() -> Self::Value {
235        0u8
236    }
237    #[inline]
238    fn into_ffi_value(self) -> Self::Value {
239        self as u8
240    }
241}
242
243unsafe impl IntoFfi for crate::ByteBuffer {
244    type Value = crate::ByteBuffer;
245    #[inline]
246    fn ffi_default() -> Self::Value {
247        crate::ByteBuffer::default()
248    }
249    #[inline]
250    fn into_ffi_value(self) -> Self::Value {
251        self
252    }
253}
254
255// just cuts down on boilerplate. Not public.
256macro_rules! impl_into_ffi_for_primitive {
257    ($($T:ty),+) => {$(
258        unsafe impl IntoFfi for $T {
259            type Value = Self;
260            #[inline] fn ffi_default() -> Self { Default::default() }
261            #[inline] fn into_ffi_value(self) -> Self { self }
262        }
263    )+}
264}
265
266// See IntoFfi docs for why this is not exhaustive
267impl_into_ffi_for_primitive![(), i8, u8, i16, u16, i32, u32, i64, u64, f32, f64];
268
269// just cuts down on boilerplate. Not public.
270macro_rules! impl_into_ffi_for_pointer {
271    ($($T:ty),+) => {$(
272        unsafe impl IntoFfi for $T {
273            type Value = Self;
274            #[inline] fn ffi_default() -> Self { ptr::null_mut() }
275            #[inline] fn into_ffi_value(self) -> Self { self }
276        }
277    )+}
278}
279
280impl_into_ffi_for_pointer![
281    *mut i8,
282    *const i8,
283    *mut u8,
284    *const u8,
285    *mut c_void,
286    *const c_void
287];