Backed out 5 changesets (bug 1890092, bug 1888683) for causing build bustages & crash...
[gecko.git] / third_party / rust / uniffi_core / src / ffi_converter_traits.rs
blob3b5914e32f4179c16983e62a02a09d5f8f8703ff
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 //! Traits that define how to transfer values via the FFI layer.
6 //!
7 //! These traits define how to pass values over the FFI in various ways: as arguments or as return
8 //! values, from Rust to the foreign side and vice-versa.  These traits are mainly used by the
9 //! proc-macro generated code.  The goal is to allow the proc-macros to go from a type name to the
10 //! correct function for a given FFI operation.
11 //!
12 //! The traits form a sort-of tree structure from general to specific:
13 //! ```ignore
14 //!
15 //!                   [FfiConverter]
16 //!                        |
17 //!           -----------------------------
18 //!           |                           |
19 //!       [Lower]                      [Lift]
20 //!           |                           |
21 //!           |                       --------------
22 //!           |                       |            |
23 //!       [LowerReturn]           [LiftRef]  [LiftReturn]
24 //! ```
25 //!
26 //! The `derive_ffi_traits` macro can be used to derive the specific traits from the general ones.
27 //! Here's the main ways we implement these traits:
28 //!
29 //! * For most types we implement [FfiConverter] and use [derive_ffi_traits] to implement the rest
30 //! * If a type can only be lifted/lowered, then we implement [Lift] or [Lower] and use
31 //!   [derive_ffi_traits] to implement the rest
32 //! * If a type needs special-case handling, like `Result<>` and `()`, we implement the traits
33 //!   directly.
34 //!
35 //! FfiConverter has a generic parameter, that's filled in with a type local to the UniFFI consumer crate.
36 //! This allows us to work around the Rust orphan rules for remote types. See
37 //! `https://mozilla.github.io/uniffi-rs/internals/lifting_and_lowering.html#code-generation-and-the-fficonverter-trait`
38 //! for details.
39 //!
40 //! ## Safety
41 //!
42 //! All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
43 //! that it's safe to pass your type out to foreign-language code and back again. Buggy
44 //! implementations of this trait might violate some assumptions made by the generated code,
45 //! or might not match with the corresponding code in the generated foreign-language bindings.
46 //! These traits should not be used directly, only in generated code, and the generated code should
47 //! have fixture tests to test that everything works correctly together.
49 use std::{borrow::Borrow, sync::Arc};
51 use anyhow::bail;
52 use bytes::Buf;
54 use crate::{FfiDefault, MetadataBuffer, Result, RustBuffer, UnexpectedUniFFICallbackError};
56 /// Generalized FFI conversions
57 ///
58 /// This trait is not used directly by the code generation, but implement this and calling
59 /// [derive_ffi_traits] is a simple way to implement all the traits that are.
60 ///
61 /// ## Safety
62 ///
63 /// All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
64 /// that it's safe to pass your type out to foreign-language code and back again. Buggy
65 /// implementations of this trait might violate some assumptions made by the generated code,
66 /// or might not match with the corresponding code in the generated foreign-language bindings.
67 /// These traits should not be used directly, only in generated code, and the generated code should
68 /// have fixture tests to test that everything works correctly together.
69 pub unsafe trait FfiConverter<UT>: Sized {
70     /// The low-level type used for passing values of this type over the FFI.
71     ///
72     /// This must be a C-compatible type (e.g. a numeric primitive, a `#[repr(C)]` struct) into
73     /// which values of the target rust type can be converted.
74     ///
75     /// For complex data types, we currently recommend using `RustBuffer` and serializing
76     /// the data for transfer. In theory it could be possible to build a matching
77     /// `#[repr(C)]` struct for a complex data type and pass that instead, but explicit
78     /// serialization is simpler and safer as a starting point.
79     ///
80     /// If a type implements multiple FFI traits, `FfiType` must be the same for all of them.
81     type FfiType: FfiDefault;
83     /// Lower a rust value of the target type, into an FFI value of type Self::FfiType.
84     ///
85     /// This trait method is used for sending data from rust to the foreign language code,
86     /// by (hopefully cheaply!) converting it into something that can be passed over the FFI
87     /// and reconstructed on the other side.
88     ///
89     /// Note that this method takes an owned value; this allows it to transfer ownership in turn to
90     /// the foreign language code, e.g. by boxing the value and passing a pointer.
91     fn lower(obj: Self) -> Self::FfiType;
93     /// Lift a rust value of the target type, from an FFI value of type Self::FfiType.
94     ///
95     /// This trait method is used for receiving data from the foreign language code in rust,
96     /// by (hopefully cheaply!) converting it from a low-level FFI value of type Self::FfiType
97     /// into a high-level rust value of the target type.
98     ///
99     /// Since we cannot statically guarantee that the foreign-language code will send valid
100     /// values of type Self::FfiType, this method is fallible.
101     fn try_lift(v: Self::FfiType) -> Result<Self>;
103     /// Write a rust value into a buffer, to send over the FFI in serialized form.
104     ///
105     /// This trait method can be used for sending data from rust to the foreign language code,
106     /// in cases where we're not able to use a special-purpose FFI type and must fall back to
107     /// sending serialized bytes.
108     ///
109     /// Note that this method takes an owned value because it's transferring ownership
110     /// to the foreign language code via the RustBuffer.
111     fn write(obj: Self, buf: &mut Vec<u8>);
113     /// Read a rust value from a buffer, received over the FFI in serialized form.
114     ///
115     /// This trait method can be used for receiving data from the foreign language code in rust,
116     /// in cases where we're not able to use a special-purpose FFI type and must fall back to
117     /// receiving serialized bytes.
118     ///
119     /// Since we cannot statically guarantee that the foreign-language code will send valid
120     /// serialized bytes for the target type, this method is fallible.
121     ///
122     /// Note the slightly unusual type here - we want a mutable reference to a slice of bytes,
123     /// because we want to be able to advance the start of the slice after reading an item
124     /// from it (but will not mutate the actual contents of the slice).
125     fn try_read(buf: &mut &[u8]) -> Result<Self>;
127     /// Type ID metadata, serialized into a [MetadataBuffer].
128     ///
129     /// If a type implements multiple FFI traits, `TYPE_ID_META` must be the same for all of them.
130     const TYPE_ID_META: MetadataBuffer;
133 /// FfiConverter for Arc-types
135 /// This trait gets around the orphan rule limitations, which prevent library crates from
136 /// implementing `FfiConverter` on an Arc. When this is implemented for T, we generate an
137 /// `FfiConverter` impl for Arc<T>.
139 /// Note: There's no need for `FfiConverterBox`, since Box is a fundamental type.
141 /// ## Safety
143 /// All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
144 /// that it's safe to pass your type out to foreign-language code and back again. Buggy
145 /// implementations of this trait might violate some assumptions made by the generated code,
146 /// or might not match with the corresponding code in the generated foreign-language bindings.
147 /// These traits should not be used directly, only in generated code, and the generated code should
148 /// have fixture tests to test that everything works correctly together.
149 pub unsafe trait FfiConverterArc<UT>: Send + Sync {
150     type FfiType: FfiDefault;
152     fn lower(obj: Arc<Self>) -> Self::FfiType;
153     fn try_lift(v: Self::FfiType) -> Result<Arc<Self>>;
154     fn write(obj: Arc<Self>, buf: &mut Vec<u8>);
155     fn try_read(buf: &mut &[u8]) -> Result<Arc<Self>>;
157     const TYPE_ID_META: MetadataBuffer;
160 unsafe impl<T, UT> FfiConverter<UT> for Arc<T>
161 where
162     T: FfiConverterArc<UT> + ?Sized,
164     type FfiType = T::FfiType;
166     fn lower(obj: Self) -> Self::FfiType {
167         T::lower(obj)
168     }
170     fn try_lift(v: Self::FfiType) -> Result<Self> {
171         T::try_lift(v)
172     }
174     fn write(obj: Self, buf: &mut Vec<u8>) {
175         T::write(obj, buf)
176     }
178     fn try_read(buf: &mut &[u8]) -> Result<Self> {
179         T::try_read(buf)
180     }
182     const TYPE_ID_META: MetadataBuffer = T::TYPE_ID_META;
185 /// Lift values passed by the foreign code over the FFI into Rust values
187 /// This is used by the code generation to handle arguments.  It's usually derived from
188 /// [FfiConverter], except for types that only support lifting but not lowering.
190 /// See [FfiConverter] for a discussion of the methods
192 /// ## Safety
194 /// All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
195 /// that it's safe to pass your type out to foreign-language code and back again. Buggy
196 /// implementations of this trait might violate some assumptions made by the generated code,
197 /// or might not match with the corresponding code in the generated foreign-language bindings.
198 /// These traits should not be used directly, only in generated code, and the generated code should
199 /// have fixture tests to test that everything works correctly together.
200 pub unsafe trait Lift<UT>: Sized {
201     type FfiType;
203     fn try_lift(v: Self::FfiType) -> Result<Self>;
205     fn try_read(buf: &mut &[u8]) -> Result<Self>;
207     /// Convenience method
208     fn try_lift_from_rust_buffer(v: RustBuffer) -> Result<Self> {
209         let vec = v.destroy_into_vec();
210         let mut buf = vec.as_slice();
211         let value = Self::try_read(&mut buf)?;
212         match Buf::remaining(&buf) {
213             0 => Ok(value),
214             n => bail!("junk data left in buffer after lifting (count: {n})",),
215         }
216     }
218     const TYPE_ID_META: MetadataBuffer;
221 /// Lower Rust values to pass them to the foreign code
223 /// This is used to pass arguments to callback interfaces. It's usually derived from
224 /// [FfiConverter], except for types that only support lowering but not lifting.
226 /// See [FfiConverter] for a discussion of the methods
228 /// ## Safety
230 /// All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
231 /// that it's safe to pass your type out to foreign-language code and back again. Buggy
232 /// implementations of this trait might violate some assumptions made by the generated code,
233 /// or might not match with the corresponding code in the generated foreign-language bindings.
234 /// These traits should not be used directly, only in generated code, and the generated code should
235 /// have fixture tests to test that everything works correctly together.
236 pub unsafe trait Lower<UT>: Sized {
237     type FfiType: FfiDefault;
239     fn lower(obj: Self) -> Self::FfiType;
241     fn write(obj: Self, buf: &mut Vec<u8>);
243     /// Convenience method
244     fn lower_into_rust_buffer(obj: Self) -> RustBuffer {
245         let mut buf = ::std::vec::Vec::new();
246         Self::write(obj, &mut buf);
247         RustBuffer::from_vec(buf)
248     }
250     const TYPE_ID_META: MetadataBuffer;
253 /// Return Rust values to the foreign code
255 /// This is usually derived from [Lift], but we special case types like `Result<>` and `()`.
257 /// ## Safety
259 /// All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
260 /// that it's safe to pass your type out to foreign-language code and back again. Buggy
261 /// implementations of this trait might violate some assumptions made by the generated code,
262 /// or might not match with the corresponding code in the generated foreign-language bindings.
263 /// These traits should not be used directly, only in generated code, and the generated code should
264 /// have fixture tests to test that everything works correctly together.
265 pub unsafe trait LowerReturn<UT>: Sized {
266     /// The type that should be returned by scaffolding functions for this type.
267     ///
268     /// When derived, it's the same as `FfiType`.
269     type ReturnType: FfiDefault;
271     /// Lower this value for scaffolding function return
272     ///
273     /// This method converts values into the `Result<>` type that [rust_call] expects. For
274     /// successful calls, return `Ok(lower_return)`.  For errors that should be translated into
275     /// thrown exceptions on the foreign code, serialize the error into a RustBuffer and return
276     /// `Err(buf)`
277     fn lower_return(obj: Self) -> Result<Self::ReturnType, RustBuffer>;
279     /// If possible, get a serialized error for failed argument lifts
280     ///
281     /// By default, we just panic and let `rust_call` handle things.  However, for `Result<_, E>`
282     /// returns, if the anyhow error can be downcast to `E`, then serialize that and return it.
283     /// This results in the foreign code throwing a "normal" exception, rather than an unexpected
284     /// exception.
285     fn handle_failed_lift(arg_name: &str, e: anyhow::Error) -> Self {
286         panic!("Failed to convert arg '{arg_name}': {e}")
287     }
289     const TYPE_ID_META: MetadataBuffer;
292 /// Return foreign values to Rust
294 /// This is usually derived from [Lower], but we special case types like `Result<>` and `()`.
296 /// ## Safety
298 /// All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
299 /// that it's safe to pass your type out to foreign-language code and back again. Buggy
300 /// implementations of this trait might violate some assumptions made by the generated code,
301 /// or might not match with the corresponding code in the generated foreign-language bindings.
302 /// These traits should not be used directly, only in generated code, and the generated code should
303 /// have fixture tests to test that everything works correctly together.
304 pub unsafe trait LiftReturn<UT>: Sized {
305     /// Lift a Rust value for a callback interface method result
306     fn lift_callback_return(buf: RustBuffer) -> Self;
308     /// Lift a Rust value for a callback interface method error result
309     ///
310     /// This is called for "expected errors" -- the callback method returns a Result<> type and the
311     /// foreign code throws an exception that corresponds to the error type.
312     fn lift_callback_error(_buf: RustBuffer) -> Self {
313         panic!("Callback interface method returned unexpected error")
314     }
316     /// Lift a Rust value for an unexpected callback interface error
317     ///
318     /// The main reason this is called is when the callback interface throws an error type that
319     /// doesn't match the Rust trait definition.  It's also called for corner cases, like when the
320     /// foreign code doesn't follow the FFI contract.
321     ///
322     /// The default implementation panics unconditionally.  Errors used in callback interfaces
323     /// handle this using the `From<UnexpectedUniFFICallbackError>` impl that the library author
324     /// must provide.
325     fn handle_callback_unexpected_error(e: UnexpectedUniFFICallbackError) -> Self {
326         panic!("Callback interface failure: {e}")
327     }
329     const TYPE_ID_META: MetadataBuffer;
332 /// Lift references
334 /// This is usually derived from [Lift] and also implemented for the inner `T` value of smart
335 /// pointers.  For example, if `Lift` is implemented for `Arc<T>`, then we implement this to lift
337 /// ## Safety
339 /// All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee
340 /// that it's safe to pass your type out to foreign-language code and back again. Buggy
341 /// implementations of this trait might violate some assumptions made by the generated code,
342 /// or might not match with the corresponding code in the generated foreign-language bindings.
343 /// These traits should not be used directly, only in generated code, and the generated code should
344 /// have fixture tests to test that everything works correctly together.
345 /// `&T` using the Arc.
346 pub unsafe trait LiftRef<UT> {
347     type LiftType: Lift<UT> + Borrow<Self>;
350 pub trait ConvertError<UT>: Sized {
351     fn try_convert_unexpected_callback_error(e: UnexpectedUniFFICallbackError) -> Result<Self>;
354 /// Derive FFI traits
356 /// This can be used to derive:
357 ///   * [Lower] and [Lift] from [FfiConverter]
358 ///   * [LowerReturn] from [Lower]
359 ///   * [LiftReturn] and [LiftRef] from [Lift]
361 /// Usage:
362 /// ```ignore
364 /// // Derive everything from [FfiConverter] for all Uniffi tags
365 /// ::uniffi::derive_ffi_traits!(blanket Foo)
366 /// // Derive everything from [FfiConverter] for the local crate::UniFfiTag
367 /// ::uniffi::derive_ffi_traits!(local Foo)
368 /// // To derive a specific trait, write out the impl item minus the actual  block
369 /// ::uniffi::derive_ffi_traits!(impl<T, UT> LowerReturn<UT> for Option<T>)
370 /// ```
371 #[macro_export]
372 #[allow(clippy::crate_in_macro_def)]
373 macro_rules! derive_ffi_traits {
374     (blanket $ty:ty) => {
375         $crate::derive_ffi_traits!(impl<UT> Lower<UT> for $ty);
376         $crate::derive_ffi_traits!(impl<UT> Lift<UT> for $ty);
377         $crate::derive_ffi_traits!(impl<UT> LowerReturn<UT> for $ty);
378         $crate::derive_ffi_traits!(impl<UT> LiftReturn<UT> for $ty);
379         $crate::derive_ffi_traits!(impl<UT> LiftRef<UT> for $ty);
380         $crate::derive_ffi_traits!(impl<UT> ConvertError<UT> for $ty);
381     };
383     (local $ty:ty) => {
384         $crate::derive_ffi_traits!(impl Lower<crate::UniFfiTag> for $ty);
385         $crate::derive_ffi_traits!(impl Lift<crate::UniFfiTag> for $ty);
386         $crate::derive_ffi_traits!(impl LowerReturn<crate::UniFfiTag> for $ty);
387         $crate::derive_ffi_traits!(impl LiftReturn<crate::UniFfiTag> for $ty);
388         $crate::derive_ffi_traits!(impl LiftRef<crate::UniFfiTag> for $ty);
389         $crate::derive_ffi_traits!(impl ConvertError<crate::UniFfiTag> for $ty);
390     };
392     (impl $(<$($generic:ident),*>)? $(::uniffi::)? Lower<$ut:path> for $ty:ty $(where $($where:tt)*)?) => {
393         unsafe impl $(<$($generic),*>)* $crate::Lower<$ut> for $ty $(where $($where)*)*
394         {
395             type FfiType = <Self as $crate::FfiConverter<$ut>>::FfiType;
397             fn lower(obj: Self) -> Self::FfiType {
398                 <Self as $crate::FfiConverter<$ut>>::lower(obj)
399             }
401             fn write(obj: Self, buf: &mut ::std::vec::Vec<u8>) {
402                 <Self as $crate::FfiConverter<$ut>>::write(obj, buf)
403             }
405             const TYPE_ID_META: $crate::MetadataBuffer = <Self as $crate::FfiConverter<$ut>>::TYPE_ID_META;
406         }
407     };
409     (impl $(<$($generic:ident),*>)? $(::uniffi::)? Lift<$ut:path> for $ty:ty $(where $($where:tt)*)?) => {
410         unsafe impl $(<$($generic),*>)* $crate::Lift<$ut> for $ty $(where $($where)*)*
411         {
412             type FfiType = <Self as $crate::FfiConverter<$ut>>::FfiType;
414             fn try_lift(v: Self::FfiType) -> $crate::deps::anyhow::Result<Self> {
415                 <Self as $crate::FfiConverter<$ut>>::try_lift(v)
416             }
418             fn try_read(buf: &mut &[u8]) -> $crate::deps::anyhow::Result<Self> {
419                 <Self as $crate::FfiConverter<$ut>>::try_read(buf)
420             }
422             const TYPE_ID_META: $crate::MetadataBuffer = <Self as $crate::FfiConverter<$ut>>::TYPE_ID_META;
423         }
424     };
426     (impl $(<$($generic:ident),*>)? $(::uniffi::)? LowerReturn<$ut:path> for $ty:ty $(where $($where:tt)*)?) => {
427         unsafe impl $(<$($generic),*>)* $crate::LowerReturn<$ut> for $ty $(where $($where)*)*
428         {
429             type ReturnType = <Self as $crate::Lower<$ut>>::FfiType;
431             fn lower_return(obj: Self) -> $crate::deps::anyhow::Result<Self::ReturnType, $crate::RustBuffer> {
432                 Ok(<Self as $crate::Lower<$ut>>::lower(obj))
433             }
435             const TYPE_ID_META: $crate::MetadataBuffer =<Self as $crate::Lower<$ut>>::TYPE_ID_META;
436         }
437     };
439     (impl $(<$($generic:ident),*>)? $(::uniffi::)? LiftReturn<$ut:path> for $ty:ty $(where $($where:tt)*)?) => {
440         unsafe impl $(<$($generic),*>)* $crate::LiftReturn<$ut> for $ty $(where $($where)*)*
441         {
442             fn lift_callback_return(buf: $crate::RustBuffer) -> Self {
443                 <Self as $crate::Lift<$ut>>::try_lift_from_rust_buffer(buf)
444                     .expect("Error reading callback interface result")
445             }
447             const TYPE_ID_META: $crate::MetadataBuffer = <Self as $crate::Lift<$ut>>::TYPE_ID_META;
448         }
449     };
451     (impl $(<$($generic:ident),*>)? $(::uniffi::)? LiftRef<$ut:path> for $ty:ty $(where $($where:tt)*)?) => {
452         unsafe impl $(<$($generic),*>)* $crate::LiftRef<$ut> for $ty $(where $($where)*)*
453         {
454             type LiftType = Self;
455         }
456     };
458     (impl $(<$($generic:ident),*>)? $(::uniffi::)? ConvertError<$ut:path> for $ty:ty $(where $($where:tt)*)?) => {
459         impl $(<$($generic),*>)* $crate::ConvertError<$ut> for $ty $(where $($where)*)*
460         {
461             fn try_convert_unexpected_callback_error(e: $crate::UnexpectedUniFFICallbackError) -> $crate::deps::anyhow::Result<Self> {
462                 $crate::convert_unexpected_error!(e, $ty)
463             }
464         }
465     };