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