1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
use crate::types::Behavior; use crate::helpers::*; impl ::quote::ToTokens for crate::Function { fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) { let ffi_name = &self.ffi_name; let ffi_args = &self.ffi_args; let ffi_output = &self.ffi_output; let call_expr = &self.call_expr; tokens.extend(::quote::quote! { #[allow(unused_imports)] use ::std::convert::TryInto as _; #[no_mangle] #[allow(unused_mut)] pub extern "C" fn #ffi_name(#(#ffi_args),*) #ffi_output { #call_expr } }); } } impl crate::Function { pub fn from_item_fn(ifn: &::syn::ItemFn) -> Self { Self { ffi_name: ifn.sig.ident.clone().prefix("ffi_"), ffi_args: ifn.sig.inputs.iter().map(|arg| arg_to_ffi_arg(arg)).collect(), ffi_output: output_to_ffi_output(&ifn.sig.output), call_expr: call_expr_from_item_fn(ifn), } } } fn arg_to_ffi_arg(arg: &::syn::FnArg) -> ::syn::FnArg { match arg { ::syn::FnArg::Receiver(_) => panic!("self receiver not handled in functions"), ::syn::FnArg::Typed(patty) => ::syn::FnArg::Typed(::syn::PatType{ pat: Box::new(*patty.pat.clone()), ty: Box::new(crate::types::switch(&patty.ty).fold(*patty.ty.clone())), ..patty.clone() }), } } fn output_to_ffi_output(output: &::syn::ReturnType) -> ::syn::ReturnType { let sty = if let ::syn::ReturnType::Type(_, sty) = output { if crate::types::Result.is(&sty) { crate::types::Result.fold(*sty.clone()) } else { crate::types::Result.fold(::syn::parse_quote! { Result<#sty, ::ffishim::library::Error> }) } } else { crate::types::Result.fold(::syn::parse_quote! { Result<(), ::ffishim::library::Error> }) }; ::syn::parse_quote! { -> #sty } } fn call_expr_from_item_fn(ifn: &::syn::ItemFn) -> ::syn::Expr { let orig_name = &ifn.sig.ident; let convert_exprs = ifn.sig.inputs.iter().map(|arg| { if let ::syn::FnArg::Typed(pat) = arg { let arg_name = pat.unwrap_ident_as_expr(); let expr = crate::types::switch(&pat.ty).try_into(&pat.ty, arg_name); crate::types::Result.try_or_return(expr) } else { panic!("no receiver (self) supported in function signatures"); } }); let call_expr: ::syn::Expr = ::syn::parse_quote! { #orig_name(#(#convert_exprs),*) }; if let ::syn::ReturnType::Type(_, sty) = &ifn.sig.output { if crate::types::Result.is(&sty) { crate::types::Result.from(sty, call_expr) } else { crate::types::Result.wrap_success(sty, call_expr) } } else { crate::types::Result.wrap_success(&::syn::parse_quote! { () }, call_expr) } }