/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
usecrate::{
default::{default_value_metadata_calls, DefaultValue},
export::{AsyncRuntime, DefaultMap, ExportFnArgs},
ffiops,
util::{create_metadata_items, ident_to_string, mod_path, try_metadata_value_from_usize},
}; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{spanned::Spanned, FnArg, Ident, Pat, Receiver, ReturnType, Type};
pub(crate) struct FnSignature { pub kind: FnKind, pub span: Span, pub mod_path: String, // The identifier of the Rust function. pub ident: Ident, // The foreign name for this function, usually == ident. pub name: String, pub is_async: bool, pub async_runtime: Option<AsyncRuntime>, pub receiver: Option<ReceiverArg>, pub args: Vec<NamedArg>, pub return_ty: TokenStream, // Does this the return type look like a result? // Only use this in UDL mode. // In general, it's not reliable because it fails for type aliases. pub looks_like_result: bool, pub docstring: String,
}
/// Generate a closure that tries to lift all arguments into a tuple. /// /// The closure moves all scaffolding arguments into itself and returns: /// - The lifted argument tuple on success /// - The field name and error on failure (`Err(&'static str, anyhow::Error>`) pubfn lift_closure(&self, self_lift: Option<TokenStream>) -> TokenStream { let arg_lifts = self.args.iter().map(|arg| { let ident = &arg.ident; let try_lift = ffiops::try_lift(&arg.ty); let name = &arg.name;
quote! { match#try_lift(#ident) {
::std::result::Result::Ok(v) => v,
::std::result::Result::Err(e) => { return ::std::result::Result::Err((#name, e))
}
}
}
}); let all_lifts = self_lift.into_iter().chain(arg_lifts);
quote! { move || ::std::result::Result::Ok(( #(#all_lifts,)*
))
}
}
/// Call a Rust function from a [Self::lift_closure] success. /// /// This takes an Ok value returned by `lift_closure` with the name `uniffi_args` and generates /// a series of parameters to pass to the Rust function. pubfn rust_call_params(&self, self_lift: bool) -> TokenStream { let start_idx = if self_lift { 1 } else { 0 }; let args = self.args.iter().enumerate().map(|(i, arg)| { let idx = syn::Index::from(i + start_idx); let ty = &arg.ty; match &arg.ref_type {
None => quote! { uniffi_args.#idx },
Some(ref_type) => quote! {
<#tyas ::std::borrow::Borrow<#ref_type>>::borrow(&uniffi_args.#idx)
},
}
});
quote! { #(#args),* }
}
/// Parameters expressions for each of our arguments pubfn params(&self) -> impl Iterator<Item = TokenStream> + '_ { self.args.iter().map(NamedArg::param)
}
/// Name of the scaffolding function to generate for this function pubfn scaffolding_fn_ident(&self) -> syn::Result<Ident> { let name = &self.name; let name = match &self.kind {
FnKind::Function => uniffi_meta::fn_symbol_name(&self.mod_path, name),
FnKind::Method { self_ident } | FnKind::TraitMethod { self_ident, .. } => {
uniffi_meta::method_symbol_name(&self.mod_path, &ident_to_string(self_ident), name)
}
FnKind::Constructor { self_ident } => uniffi_meta::constructor_symbol_name(
&self.mod_path,
&ident_to_string(self_ident),
name,
),
};
Ok(Ident::new(&name, Span::call_site()))
}
/// Scaffolding parameters expressions for each of our arguments pubfn scaffolding_param_names(&self) -> impl Iterator<Item = TokenStream> + '_ { self.args.iter().map(|a| { let ident = &a.ident;
quote! { #ident }
})
}
/// Generate metadata items for this function pub(crate) fn metadata_expr(&self) -> syn::Result<TokenStream> { letSelf {
name,
return_ty,
is_async,
mod_path,
docstring,
..
} = &self; let args_len = try_metadata_value_from_usize( // Use param_lifts to calculate this instead of sig.inputs to avoid counting any self // params self.args.len(), "UniFFI limits functions to 256 arguments",
)?; let arg_metadata_calls = self
.args
.iter()
.map(NamedArg::arg_metadata)
.collect::<syn::Result<Vec<_>>>()?;
let type_id_meta = ffiops::type_id_meta(return_ty);
impl From<Receiver> for ReceiverArg { fn from(receiver: Receiver) -> Self { ifletType::Path(p) = *receiver.ty { iflet Some(segment) = p.path.segments.last() { // This comparison will fail if a user uses a typedef for Arc. Maybe we could // implement some system like TYPE_ID_META to figure this out from the type system. // However, this seems good enough for now. if segment.ident == "Arc" { return ReceiverArg::Arc;
}
}
} Self::Ref
}
}
/// Generate the parameter for this Arg pub(crate) fn param(&self) -> TokenStream { let ident = &self.ident; let ty = &self.ty;
quote! { #ident: #ty }
}
pub(crate) fn arg_metadata(&self) -> syn::Result<TokenStream> { let name = &self.name; let type_id_meta = ffiops::type_id_meta(&self.ty); let default_calls = default_value_metadata_calls(&self.default)?;
Ok(quote! {
.concat_str(#name)
.concat(#type_id_meta) #default_calls
})
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.