diff --git a/ffi/derive/src/derive.rs b/ffi/derive/src/derive.rs index 4bb40243f29..19d46c2b90a 100644 --- a/ffi/derive/src/derive.rs +++ b/ffi/derive/src/derive.rs @@ -169,8 +169,8 @@ fn gen_ffi_derive(item_name: &Ident, field: &syn::Field, derive: Derive) -> syn: let (ffi_fn_args, ffi_fn_body) = match derive { Derive::Setter => { let (handle_arg, field_arg) = ( - Receiver::new(&self_ty, handle_name, parse_quote! {&mut Self}), - InputArg::new(&self_ty, field_name, field_ty), + Receiver::new(Some(&self_ty), handle_name, parse_quote! {&mut Self}), + InputArg::new(Some(&self_ty), field_name, field_ty), ); ( @@ -182,8 +182,8 @@ fn gen_ffi_derive(item_name: &Ident, field: &syn::Field, derive: Derive) -> syn: let field_ty = parse_quote! {&#field_ty}; let (handle_arg, field_arg) = ( - Receiver::new(&self_ty, handle_name, parse_quote! {&Self}), - ReturnArg::new(&self_ty, field_name.clone(), &field_ty), + Receiver::new(Some(&self_ty), handle_name, parse_quote! {&Self}), + ReturnArg::new(Some(&self_ty), field_name.clone(), &field_ty), ); ( @@ -195,8 +195,8 @@ fn gen_ffi_derive(item_name: &Ident, field: &syn::Field, derive: Derive) -> syn: let field_ty = parse_quote! {&mut #field_ty}; let (handle_arg, field_arg) = ( - Receiver::new(&self_ty, handle_name, parse_quote! {&mut Self}), - ReturnArg::new(&self_ty, field_name.clone(), &field_ty), + Receiver::new(Some(&self_ty), handle_name, parse_quote! {&mut Self}), + ReturnArg::new(Some(&self_ty), field_name.clone(), &field_ty), ); ( diff --git a/ffi/derive/src/export.rs b/ffi/derive/src/export.rs index 51ab17e86bb..d30e1163676 100644 --- a/ffi/derive/src/export.rs +++ b/ffi/derive/src/export.rs @@ -21,14 +21,28 @@ pub fn gen_ffi_fn(fn_descriptor: &FnDescriptor) -> TokenStream { let output_arg = ffi_output_arg(fn_descriptor).map(gen_ffi_fn_out_ptr_arg); let ffi_fn_body = gen_fn_body(fn_descriptor); - let ffi_fn_doc = format!( - " FFI function equivalent of [`{}::{}`]\n \ + let ffi_fn_doc = fn_descriptor.self_ty.map_or_else( + || { + format!( + " FFI function equivalent of [`{}`]\n \ \n \ # Safety\n \ \n \ All of the given pointers must be valid", - fn_descriptor.self_ty.get_ident().expect_or_abort("Defined"), - fn_descriptor.method_name + fn_descriptor.method_name + ) + }, + |self_ty| { + format!( + " FFI function equivalent of [`{}::{}`]\n \ + \n \ + # Safety\n \ + \n \ + All of the given pointers must be valid", + self_ty.get_ident().expect_or_abort("Defined"), + fn_descriptor.method_name + ) + }, ); quote! { @@ -58,11 +72,19 @@ pub fn gen_ffi_fn(fn_descriptor: &FnDescriptor) -> TokenStream { } fn gen_ffi_fn_name(fn_descriptor: &FnDescriptor) -> Ident { - let self_ty_name = fn_descriptor.self_ty_name(); - - Ident::new( - &format!("{}__{}", self_ty_name, fn_descriptor.method_name), - Span::call_site(), + fn_descriptor.self_ty_name().map_or_else( + || { + Ident::new( + &format!("__{}", fn_descriptor.method_name), + Span::call_site(), + ) + }, + |self_ty_name| { + Ident::new( + &format!("{}__{}", self_ty_name, fn_descriptor.method_name), + Span::call_site(), + ) + }, ) } @@ -114,7 +136,11 @@ fn gen_method_call_stmt(fn_descriptor: &FnDescriptor) -> TokenStream { }); let fn_arg_names = fn_descriptor.input_args.iter().map(Arg::name); - let method_call = quote! {#self_type::#method_name(#(#self_arg_name,)* #(#fn_arg_names),*)}; + let method_call = if let Some(self_type) = self_type { + quote! {#self_type::#method_name(#(#self_arg_name,)* #(#fn_arg_names),*)} + } else { + quote! {#method_name(#(#self_arg_name,)* #(#fn_arg_names),*)} + }; fn_descriptor.output_arg.as_ref().map_or_else( || quote! {#method_call;}, diff --git a/ffi/derive/src/impl_visitor.rs b/ffi/derive/src/impl_visitor.rs index c0e83bb3b43..950b46cbf07 100644 --- a/ffi/derive/src/impl_visitor.rs +++ b/ffi/derive/src/impl_visitor.rs @@ -12,19 +12,19 @@ pub trait Arg { #[derive(Constructor)] pub struct Receiver<'ast> { - self_ty: &'ast syn::Path, + self_ty: Option<&'ast syn::Path>, name: Ident, type_: Type, } pub struct InputArg<'ast> { - self_ty: &'ast syn::Path, + self_ty: Option<&'ast syn::Path>, name: &'ast Ident, type_: &'ast Type, } pub struct ReturnArg<'ast> { - self_ty: &'ast syn::Path, + self_ty: Option<&'ast syn::Path>, name: Ident, type_: &'ast Type, } @@ -37,7 +37,7 @@ pub struct ImplDescriptor<'ast> { } impl<'ast> InputArg<'ast> { - pub fn new(self_ty: &'ast syn::Path, name: &'ast Ident, type_: &'ast Type) -> Self { + pub fn new(self_ty: Option<&'ast syn::Path>, name: &'ast Ident, type_: &'ast Type) -> Self { Self { self_ty, name, @@ -47,7 +47,7 @@ impl<'ast> InputArg<'ast> { } impl<'ast> ReturnArg<'ast> { - pub fn new(self_ty: &'ast syn::Path, name: Ident, type_: &'ast Type) -> Self { + pub fn new(self_ty: Option<&'ast syn::Path>, name: Ident, type_: &'ast Type) -> Self { Self { self_ty, name, @@ -101,14 +101,14 @@ impl Arg for ReturnArg<'_> { } } -fn resolve_src_type(self_ty: &syn::Path, mut arg_type: Type) -> Type { +fn resolve_src_type(self_ty: Option<&syn::Path>, mut arg_type: Type) -> Type { SelfResolver::new(self_ty).visit_type_mut(&mut arg_type); ImplTraitResolver.visit_type_mut(&mut arg_type); arg_type } -fn resolve_ffi_type(self_ty: &syn::Path, mut arg_type: Type, is_output: bool) -> Type { +fn resolve_ffi_type(self_ty: Option<&syn::Path>, mut arg_type: Type, is_output: bool) -> Type { SelfResolver::new(self_ty).visit_type_mut(&mut arg_type); ImplTraitResolver.visit_type_mut(&mut arg_type); @@ -135,7 +135,7 @@ fn resolve_ffi_type(self_ty: &syn::Path, mut arg_type: Type, is_output: bool) -> pub struct FnDescriptor<'ast> { /// Resolved type of the `Self` type - pub self_ty: &'ast syn::Path, + pub self_ty: Option<&'ast syn::Path>, /// Function documentation pub doc: syn::LitStr, @@ -161,7 +161,7 @@ struct ImplVisitor<'ast> { struct FnVisitor<'ast> { /// Resolved type of the `Self` type - self_ty: &'ast syn::Path, + self_ty: Option<&'ast syn::Path>, /// Function documentation doc: Option, @@ -195,7 +195,10 @@ impl<'ast> ImplDescriptor<'ast> { } impl<'ast> FnDescriptor<'ast> { - fn from_impl_method(self_ty: &'ast syn::Path, node: &'ast syn::ImplItemMethod) -> Self { + pub(crate) fn from_impl_method( + self_ty: Option<&'ast syn::Path>, + node: &'ast syn::ImplItemMethod, + ) -> Self { let mut visitor = FnVisitor::new(self_ty); visitor.visit_impl_item_method(node); @@ -213,8 +216,8 @@ impl<'ast> FnDescriptor<'ast> { } } - pub fn self_ty_name(&self) -> &Ident { - get_ident(self.self_ty) + pub fn self_ty_name(&self) -> Option<&Ident> { + self.self_ty.map(get_ident) } } @@ -242,7 +245,7 @@ impl<'ast> ImplVisitor<'ast> { } impl<'ast> FnVisitor<'ast> { - pub const fn new(self_ty: &'ast syn::Path) -> Self { + pub const fn new(self_ty: Option<&'ast syn::Path>) -> Self { Self { self_ty, @@ -329,7 +332,7 @@ impl<'ast> Visit<'ast> for ImplVisitor<'ast> { syn::ImplItem::Method(method) => { let self_ty = self.self_ty.expect_or_abort("Defined"); self.fns - .push(FnDescriptor::from_impl_method(self_ty, method)) + .push(FnDescriptor::from_impl_method(Some(self_ty), method)) } syn::ImplItem::Type(type_) => { self.associated_types.push((&type_.ident, &type_.ty)); @@ -449,11 +452,11 @@ impl<'ast> Visit<'ast> for FnVisitor<'ast> { /// Visitor replaces all occurrences of `Self` in a path type with a fully qualified type struct SelfResolver<'ast> { - self_ty: &'ast syn::Path, + self_ty: Option<&'ast syn::Path>, } impl<'ast> SelfResolver<'ast> { - fn new(self_ty: &'ast syn::Path) -> Self { + fn new(self_ty: Option<&'ast syn::Path>) -> Self { Self { self_ty } } } @@ -468,7 +471,12 @@ impl VisitMut for SelfResolver<'_> { } if node.segments[0].ident == "Self" { - let mut node_segments = self.self_ty.segments.clone(); + #[allow(clippy::expect_used)] + let mut node_segments = self + .self_ty + .expect("Self type path expected") + .segments + .clone(); for segment in core::mem::take(&mut node.segments).into_iter().skip(1) { node_segments.push(segment); diff --git a/ffi/derive/src/lib.rs b/ffi/derive/src/lib.rs index a16af0f1710..e36ac6ff2fd 100644 --- a/ffi/derive/src/lib.rs +++ b/ffi/derive/src/lib.rs @@ -2,15 +2,12 @@ use derive::gen_fns_from_derives; use export::gen_ffi_fn; -use impl_visitor::ImplDescriptor; +use impl_visitor::{FnDescriptor, ImplDescriptor}; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use proc_macro_error::abort; -use quote::{format_ident, quote}; -use syn::{ - parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, Attribute, FnArg, Ident, - Item, ItemFn, ReturnType, -}; +use quote::{quote, ToTokens}; +use syn::{parse_macro_input, parse_quote, Attribute, Ident, Item}; mod derive; mod export; @@ -64,7 +61,17 @@ pub fn ffi_export(_attr: TokenStream, item: TokenStream) -> TokenStream { abort!(item.sig.generics, "Generics are not supported"); } - gen_ffi_fn_from_fn(item) + #[allow(clippy::expect_used)] + let impl_method = + syn::parse(item.to_token_stream().into()).expect("Can't parse fn item"); + + let impl_descriptor = FnDescriptor::from_impl_method(None, &impl_method); + let ffi_fn = gen_ffi_fn(&impl_descriptor); + quote! { + #item + + #ffi_fn + } } item => abort!(item, "Item not supported"), } @@ -457,46 +464,3 @@ fn enum_size(enum_name: &Ident, repr: &[syn::NestedMeta]) -> TokenStream2 { abort!(enum_name, "Enum doesn't have a valid representation") } } - -fn gen_ffi_fn_from_fn(item: ItemFn) -> TokenStream2 { - let signature = item.sig; - let ident = format_ident!("__{}", signature.ident); - let inputs: Punctuated = - signature.inputs.into_iter().map(gen_ffi_fn_arg).collect(); - let output = gen_ffi_fn_output(signature.output); - let body = item.block; - - let result = quote! { - #[no_mangle] - pub extern "C" fn #ident<'a>(#inputs) #output - #body - }; - // println!("{}", result.to_string()); - - result -} - -fn gen_ffi_fn_arg(arg: FnArg) -> FnArg { - let mut arg = match arg { - FnArg::Typed(arg) => arg, - _ => unreachable!(), - }; - - let ty = arg.ty; - let tokens: TokenStream = quote!(<#ty as iroha_ffi::TryFromReprC>::Source).into(); - arg.ty = syn::parse::>(tokens).expect("Can't generate FFI type"); - - arg.into() -} - -fn gen_ffi_fn_output(output: ReturnType) -> ReturnType { - let (arrow, ty) = match output { - ReturnType::Type(arrow, ty) => (arrow, ty), - ReturnType::Default => return output, - }; - - let ty = quote!(<#ty as iroha_ffi::IntoFfi>::Target).into(); - let ty = syn::parse::>(ty).expect("Can't generate FFI type"); - - ReturnType::Type(arrow, ty) -} diff --git a/ffi/derive/tests/ui_pass/valid.rs b/ffi/derive/tests/ui_pass/valid.rs index 756ed197f54..8cdcfa2abb6 100644 --- a/ffi/derive/tests/ui_pass/valid.rs +++ b/ffi/derive/tests/ui_pass/valid.rs @@ -50,16 +50,17 @@ impl FfiStruct { } } +/// Test #[ffi_export] -fn ffi_func(a: i64, b: i64) -> i64 { +pub fn ffi_func(a: i64, b: i64) -> i64 { a + b } -#[ffi_export] -fn ffi_func2(a: String, b: &[u32]) -> String { - format!("{}{}", a, b) -} - +// #[ffi_export] +// fn ffi_func2(a: String, b: &[u32]) -> String { + // format!("{}{}", a, b) +// } +// fn main() { let name = Name("X"); @@ -92,7 +93,7 @@ fn main() { __drop(FfiStruct::ID, ffi_struct.into_ffi().cast()); } - assert_eq!(5, __ffi_func(3, 2) as i64) ; - + // assert_eq!(5, __ffi_func(3, 2) as i64) ; +// // dbg!(__ffi_func2("Iroha".into(), &[1,2,3])); }