summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_macros/src/export.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi_macros/src/export.rs')
-rw-r--r--third_party/rust/uniffi_macros/src/export.rs163
1 files changed, 163 insertions, 0 deletions
diff --git a/third_party/rust/uniffi_macros/src/export.rs b/third_party/rust/uniffi_macros/src/export.rs
new file mode 100644
index 0000000000..0910f1f602
--- /dev/null
+++ b/third_party/rust/uniffi_macros/src/export.rs
@@ -0,0 +1,163 @@
+/* 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 std::collections::BTreeMap;
+
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote, quote_spanned};
+use uniffi_meta::{checksum, FnMetadata, MethodMetadata, Type};
+
+pub(crate) mod metadata;
+mod scaffolding;
+
+pub use self::metadata::gen_metadata;
+use self::scaffolding::{gen_fn_scaffolding, gen_method_scaffolding};
+use crate::{
+ export::metadata::convert::convert_type,
+ util::{assert_type_eq, create_metadata_static_var},
+};
+
+// TODO(jplatte): Ensure no generics, no async, …
+// TODO(jplatte): Aggregate errors instead of short-circuiting, whereever possible
+
+pub enum ExportItem {
+ Function {
+ sig: Box<syn::Signature>,
+ metadata: FnMetadata,
+ },
+ Impl {
+ self_ident: Ident,
+ methods: Vec<syn::Result<Method>>,
+ },
+}
+
+pub struct Method {
+ item: syn::ImplItemMethod,
+ metadata: MethodMetadata,
+}
+
+pub fn expand_export(metadata: ExportItem, mod_path: &[String]) -> TokenStream {
+ match metadata {
+ ExportItem::Function { sig, metadata } => {
+ let checksum = checksum(&metadata);
+ let scaffolding = gen_fn_scaffolding(&sig, mod_path, checksum);
+ let type_assertions = fn_type_assertions(&sig);
+ let meta_static_var = create_metadata_static_var(&sig.ident, metadata.into());
+
+ quote! {
+ #scaffolding
+ #type_assertions
+ #meta_static_var
+ }
+ }
+ ExportItem::Impl {
+ methods,
+ self_ident,
+ } => {
+ let method_tokens: TokenStream = methods
+ .into_iter()
+ .map(|res| {
+ res.map_or_else(
+ syn::Error::into_compile_error,
+ |Method { item, metadata }| {
+ let checksum = checksum(&metadata);
+ let scaffolding =
+ gen_method_scaffolding(&item.sig, mod_path, checksum, &self_ident);
+ let type_assertions = fn_type_assertions(&item.sig);
+ let meta_static_var = create_metadata_static_var(
+ &format_ident!("{}_{}", metadata.self_name, item.sig.ident),
+ metadata.into(),
+ );
+
+ quote! {
+ #scaffolding
+ #type_assertions
+ #meta_static_var
+ }
+ },
+ )
+ })
+ .collect();
+
+ quote_spanned! {self_ident.span()=>
+ ::uniffi::deps::static_assertions::assert_type_eq_all!(
+ #self_ident,
+ crate::uniffi_types::#self_ident
+ );
+
+ #method_tokens
+ }
+ }
+ }
+}
+
+fn fn_type_assertions(sig: &syn::Signature) -> TokenStream {
+ // Convert uniffi_meta::Type back to a Rust type
+ fn convert_type_back(ty: &Type) -> TokenStream {
+ match &ty {
+ Type::U8 => quote! { ::std::primitive::u8 },
+ Type::U16 => quote! { ::std::primitive::u16 },
+ Type::U32 => quote! { ::std::primitive::u32 },
+ Type::U64 => quote! { ::std::primitive::u64 },
+ Type::I8 => quote! { ::std::primitive::i8 },
+ Type::I16 => quote! { ::std::primitive::i16 },
+ Type::I32 => quote! { ::std::primitive::i32 },
+ Type::I64 => quote! { ::std::primitive::i64 },
+ Type::F32 => quote! { ::std::primitive::f32 },
+ Type::F64 => quote! { ::std::primitive::f64 },
+ Type::Bool => quote! { ::std::primitive::bool },
+ Type::String => quote! { ::std::string::String },
+ Type::Option { inner_type } => {
+ let inner = convert_type_back(inner_type);
+ quote! { ::std::option::Option<#inner> }
+ }
+ Type::Vec { inner_type } => {
+ let inner = convert_type_back(inner_type);
+ quote! { ::std::vec::Vec<#inner> }
+ }
+ Type::HashMap {
+ key_type,
+ value_type,
+ } => {
+ let key = convert_type_back(key_type);
+ let value = convert_type_back(value_type);
+ quote! { ::std::collections::HashMap<#key, #value> }
+ }
+ Type::ArcObject { object_name } => {
+ let object_ident = format_ident!("{object_name}");
+ quote! { ::std::sync::Arc<crate::uniffi_types::#object_ident> }
+ }
+ Type::Unresolved { name } => {
+ let ident = format_ident!("{name}");
+ quote! { crate::uniffi_types::#ident }
+ }
+ }
+ }
+
+ let input_types = sig.inputs.iter().filter_map(|input| match input {
+ syn::FnArg::Receiver(_) => None,
+ syn::FnArg::Typed(pat_ty) => match &*pat_ty.pat {
+ // Self type is asserted separately for impl blocks
+ syn::Pat::Ident(i) if i.ident == "self" => None,
+ _ => Some(&pat_ty.ty),
+ },
+ });
+ let output_type = match &sig.output {
+ syn::ReturnType::Default => None,
+ syn::ReturnType::Type(_, ty) => Some(ty),
+ };
+
+ let type_assertions: BTreeMap<_, _> = input_types
+ .chain(output_type)
+ .filter_map(|ty| {
+ convert_type(ty).ok().map(|meta_ty| {
+ let expected_ty = convert_type_back(&meta_ty);
+ let assert = assert_type_eq(ty, expected_ty);
+ (meta_ty, assert)
+ })
+ })
+ .collect();
+
+ type_assertions.into_values().collect()
+}