/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use crate::util::{derive_all_ffi_traits, ident_to_string, mod_path, tagged_impl_header}; use proc_macro2::{Ident, TokenStream}; use quote::quote; use syn::Path; // Generate an FfiConverter impl based on the UniffiCustomTypeConverter // implementation that the library supplies pub(crate) fn expand_ffi_converter_custom_type( ident: &Ident, builtin: &Path, udl_mode: bool, ) -> syn::Result { let impl_spec = tagged_impl_header("FfiConverter", ident, udl_mode); let derive_ffi_traits = derive_all_ffi_traits(ident, udl_mode); let name = ident_to_string(ident); let mod_path = mod_path()?; Ok(quote! { #[automatically_derived] unsafe #impl_spec { // Note: the builtin type needs to implement both `Lower` and `Lift'. We use the // `Lower` trait to get the associated type `FfiType` and const `TYPE_ID_META`. These // can't differ between `Lower` and `Lift`. type FfiType = <#builtin as ::uniffi::Lower>::FfiType; fn lower(obj: #ident ) -> Self::FfiType { <#builtin as ::uniffi::Lower>::lower(<#ident as crate::UniffiCustomTypeConverter>::from_custom(obj)) } fn try_lift(v: Self::FfiType) -> uniffi::Result<#ident> { <#ident as crate::UniffiCustomTypeConverter>::into_custom(<#builtin as ::uniffi::Lift>::try_lift(v)?) } fn write(obj: #ident, buf: &mut Vec) { <#builtin as ::uniffi::Lower>::write(<#ident as crate::UniffiCustomTypeConverter>::from_custom(obj), buf); } fn try_read(buf: &mut &[u8]) -> uniffi::Result<#ident> { <#ident as crate::UniffiCustomTypeConverter>::into_custom(<#builtin as ::uniffi::Lift>::try_read(buf)?) } const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_CUSTOM) .concat_str(#mod_path) .concat_str(#name) .concat(<#builtin as ::uniffi::Lower>::TYPE_ID_META); } #derive_ffi_traits }) } // Generate an FfiConverter impl *and* an UniffiCustomTypeConverter. pub(crate) fn expand_ffi_converter_custom_newtype( ident: &Ident, builtin: &Path, udl_mode: bool, ) -> syn::Result { let ffi_converter = expand_ffi_converter_custom_type(ident, builtin, udl_mode)?; let type_converter = custom_ffi_type_converter(ident, builtin)?; Ok(quote! { #ffi_converter #type_converter }) } fn custom_ffi_type_converter(ident: &Ident, builtin: &Path) -> syn::Result { Ok(quote! { impl crate::UniffiCustomTypeConverter for #ident { type Builtin = #builtin; fn into_custom(val: Self::Builtin) -> uniffi::Result { Ok(#ident(val)) } fn from_custom(obj: Self) -> Self::Builtin { obj.0 } } }) }