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/. */
4 
5 use crate::util::{derive_all_ffi_traits, ident_to_string, mod_path, tagged_impl_header};
6 use proc_macro2::{Ident, TokenStream};
7 use quote::quote;
8 use syn::Path;
9 
10 // Generate an FfiConverter impl based on the UniffiCustomTypeConverter
11 // implementation that the library supplies
expand_ffi_converter_custom_type( ident: &Ident, builtin: &Path, udl_mode: bool, ) -> syn::Result<TokenStream>12 pub(crate) fn expand_ffi_converter_custom_type(
13     ident: &Ident,
14     builtin: &Path,
15     udl_mode: bool,
16 ) -> syn::Result<TokenStream> {
17     let impl_spec = tagged_impl_header("FfiConverter", ident, udl_mode);
18     let derive_ffi_traits = derive_all_ffi_traits(ident, udl_mode);
19     let name = ident_to_string(ident);
20     let mod_path = mod_path()?;
21 
22     Ok(quote! {
23         #[automatically_derived]
24         unsafe #impl_spec {
25             // Note: the builtin type needs to implement both `Lower` and `Lift'.  We use the
26             // `Lower` trait to get the associated type `FfiType` and const `TYPE_ID_META`.  These
27             // can't differ between `Lower` and `Lift`.
28             type FfiType = <#builtin as ::uniffi::Lower<crate::UniFfiTag>>::FfiType;
29             fn lower(obj: #ident ) -> Self::FfiType {
30                 <#builtin as ::uniffi::Lower<crate::UniFfiTag>>::lower(<#ident as crate::UniffiCustomTypeConverter>::from_custom(obj))
31             }
32 
33             fn try_lift(v: Self::FfiType) -> uniffi::Result<#ident> {
34                 <#ident as crate::UniffiCustomTypeConverter>::into_custom(<#builtin as ::uniffi::Lift<crate::UniFfiTag>>::try_lift(v)?)
35             }
36 
37             fn write(obj: #ident, buf: &mut Vec<u8>) {
38                 <#builtin as ::uniffi::Lower<crate::UniFfiTag>>::write(<#ident as crate::UniffiCustomTypeConverter>::from_custom(obj), buf);
39             }
40 
41             fn try_read(buf: &mut &[u8]) -> uniffi::Result<#ident> {
42                 <#ident as crate::UniffiCustomTypeConverter>::into_custom(<#builtin as ::uniffi::Lift<crate::UniFfiTag>>::try_read(buf)?)
43             }
44 
45             const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_CUSTOM)
46                 .concat_str(#mod_path)
47                 .concat_str(#name)
48                 .concat(<#builtin as ::uniffi::Lower<crate::UniFfiTag>>::TYPE_ID_META);
49         }
50 
51         #derive_ffi_traits
52     })
53 }
54 
55 // Generate an FfiConverter impl *and* an UniffiCustomTypeConverter.
expand_ffi_converter_custom_newtype( ident: &Ident, builtin: &Path, udl_mode: bool, ) -> syn::Result<TokenStream>56 pub(crate) fn expand_ffi_converter_custom_newtype(
57     ident: &Ident,
58     builtin: &Path,
59     udl_mode: bool,
60 ) -> syn::Result<TokenStream> {
61     let ffi_converter = expand_ffi_converter_custom_type(ident, builtin, udl_mode)?;
62     let type_converter = custom_ffi_type_converter(ident, builtin)?;
63 
64     Ok(quote! {
65         #ffi_converter
66 
67         #type_converter
68     })
69 }
70 
custom_ffi_type_converter(ident: &Ident, builtin: &Path) -> syn::Result<TokenStream>71 fn custom_ffi_type_converter(ident: &Ident, builtin: &Path) -> syn::Result<TokenStream> {
72     Ok(quote! {
73         impl crate::UniffiCustomTypeConverter for #ident {
74             type Builtin = #builtin;
75 
76             fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
77                 Ok(#ident(val))
78             }
79 
80             fn from_custom(obj: Self) -> Self::Builtin {
81                 obj.0
82             }
83         }
84     })
85 }
86