use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
-use syn::Error;
use syn::spanned::Spanned;
+use syn::Error;
use crate::attribs::FunctionAttrs;
}
}
-enum Return {
+struct Return {
+ result: bool,
+ value: ReturnValue,
+}
+
+enum ReturnValue {
/// Return nothing. (This is different from returning an implicit undef!)
- None(bool),
+ None,
/// Return a single element.
- Single(bool),
+ Single,
/// We support tuple return types. They act like "list" return types in perl.
- Tuple(bool, usize),
+ Tuple(usize),
}
pub fn handle_function(
}
let name = func.sig.ident.clone();
- let export_public = export_public.then(|| &func.vis);
+ let export_public = export_public.then_some(&func.vis);
let xs_name = attr
.xs_name
.clone()
.unwrap_or_else(|| match mangled_package_name {
- None => Ident::new(&format!("xs_{}", name), name.span()),
- Some(prefix) => Ident::new(&format!("xs_{}_{}", prefix, name), name.span()),
+ None => Ident::new(&format!("xs_{name}"), name.span()),
+ Some(prefix) => Ident::new(&format!("xs_{prefix}_{name}"), name.span()),
});
- let impl_xs_name = Ident::new(&format!("impl_xs_{}", name), name.span());
+ let impl_xs_name = Ident::new(&format!("impl_xs_{name}"), name.span());
let mut trailing_options = 0;
let mut extract_arguments = TokenStream::new();
continue;
}
- let extracted_name = Ident::new(&format!("extracted_arg_{}", arg_name), arg_name.span());
+ let extracted_name = Ident::new(&format!("extracted_arg_{arg_name}"), arg_name.span());
let deserialized_name =
- Ident::new(&format!("deserialized_arg_{}", arg_name), arg_name.span());
+ Ident::new(&format!("deserialized_arg_{arg_name}"), arg_name.span());
let missing_message = syn::LitStr::new(
- &format!("missing required parameter: '{}'\n", arg_name),
+ &format!("missing required parameter: '{arg_name}'\n"),
arg_name.span(),
);
}
let has_return_value = match &func.sig.output {
- syn::ReturnType::Default => Return::None(false),
- syn::ReturnType::Type(_arrow, ty) => match get_result_type(&**ty) {
- (syn::Type::Tuple(tuple), result) if tuple.elems.is_empty() => Return::None(result),
- (syn::Type::Tuple(tuple), result) => Return::Tuple(result, tuple.elems.len()),
- (_, result) => Return::Single(result),
+ syn::ReturnType::Default => Return {
+ result: false,
+ value: ReturnValue::None,
+ },
+ syn::ReturnType::Type(_arrow, ty) => match get_result_type(ty) {
+ (syn::Type::Tuple(tuple), result) if tuple.elems.is_empty() => Return {
+ result,
+ value: ReturnValue::None,
+ },
+ (syn::Type::Tuple(tuple), result) => Return {
+ result,
+ value: ReturnValue::Tuple(tuple.elems.len()),
+ },
+ (_, result) => Return {
+ result,
+ value: ReturnValue::Single,
+ },
},
};
.into_raw());
}
- drop(args);
+ //drop(args);
#deserialized_arguments
};
let (cv_arg_name, cv_arg_passed) = if cv_arg {
- (quote! { cv }, quote! { cv })
+ (
+ quote! { cv },
+ quote! { ::perlmod::Value::from_raw_ref(cv as *mut ::perlmod::ffi::SV) },
+ )
} else {
(quote! { _cv }, TokenStream::new())
};
+ let return_error = if ret.result {
+ if attr.serialize_error {
+ quote! {
+ match ::perlmod::to_value(&err) {
+ Ok(err) => return Err(err.into_mortal().into_raw()),
+ Err(err) => {
+ return Err(::perlmod::Value::new_string(&format!("{}\n", err))
+ .into_mortal()
+ .into_raw());
+ }
+ }
+ }
+ } else {
+ quote! {
+ return Err(::perlmod::Value::new_string(&format!("{}\n", err))
+ .into_mortal()
+ .into_raw());
+ }
+ }
+ } else {
+ TokenStream::new()
+ };
+
+ let copy_errno = if attr.errno {
+ quote! { ::perlmod::error::copy_errno_to_libc(); }
+ } else {
+ TokenStream::new()
+ };
+
let pthx = crate::pthx_param();
- match ret {
- Return::None(result) => {
+ match ret.value {
+ ReturnValue::None => {
return_type = quote! { () };
if attr.raw_return {
bail!(&attr.raw_return => "raw_return attribute is illegal without a return value");
}
- if result {
+ if ret.result {
handle_return = quote! {
match #name(#passed_arguments) {
Ok(()) => (),
- Err(err) => {
- return Err(::perlmod::Value::new_string(&format!("{}\n", err))
- .into_mortal()
- .into_raw());
- }
+ Err(err) => { #return_error }
}
Ok(())
wrapper_func = quote! {
#[doc(hidden)]
- #vis extern "C" fn #xs_name(#pthx #cv_arg_name: &::perlmod::ffi::CV) {
+ #vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
unsafe {
- match #impl_xs_name(#cv_arg_passed) {
+ let res = #impl_xs_name(#cv_arg_passed);
+ #copy_errno
+ match res {
Ok(()) => (),
Err(sv) => ::perlmod::ffi::croak(sv),
}
}
};
}
- Return::Single(result) => {
+ ReturnValue::Single => {
return_type = quote! { *mut ::perlmod::ffi::SV };
- if result {
+ if ret.result {
handle_return = quote! {
let result = match #name(#passed_arguments) {
Ok(output) => output,
- Err(err) => {
- return Err(::perlmod::Value::new_string(&format!("{}\n", err))
- .into_mortal()
- .into_raw());
- }
+ Err(err) => { #return_error }
};
};
} else {
wrapper_func = quote! {
#[doc(hidden)]
- #vis extern "C" fn #xs_name(#pthx #cv_arg_name: &::perlmod::ffi::CV) {
+ #vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
unsafe {
- match #impl_xs_name(#cv_arg_passed) {
+ let res = #impl_xs_name(#cv_arg_passed);
+ #copy_errno
+ match res {
Ok(sv) => ::perlmod::ffi::stack_push_raw(sv),
Err(sv) => ::perlmod::ffi::croak(sv),
}
}
};
}
- Return::Tuple(result, count) => {
+ ReturnValue::Tuple(count) => {
return_type = {
let mut rt = TokenStream::new();
for _ in 0..count {
quote! { (#rt) }
};
- if result {
+ if ret.result {
handle_return = quote! {
let result = match #name(#passed_arguments) {
Ok(output) => output,
- Err(err) => {
- return Err(::perlmod::Value::new_string(&format!("{}\n", err))
- .into_mortal()
- .into_raw());
- }
+ Err(err) => { #return_error }
};
};
} else {
handle_return = quote! {
- let result = match #name(#passed_arguments);
+ let result = #name(#passed_arguments);
};
}
wrapper_func = quote! {
#[doc(hidden)]
- #vis extern "C" fn #xs_name(#pthx #cv_arg_name: &::perlmod::ffi::CV) {
+ #vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
unsafe {
- match #impl_xs_name(#cv_arg_passed) {
+ let res = #impl_xs_name(#cv_arg_passed);
+ #copy_errno
+ match res {
Ok(sv) => { #push },
Err(sv) => ::perlmod::ffi::croak(sv),
}
/// Get a non-suffixed integer from an usize.
fn simple_usize(i: usize, span: Span) -> syn::LitInt {
- syn::LitInt::new(&format!("{}", i), span)
+ syn::LitInt::new(&format!("{i}"), span)
}
/// Note that we cannot handle renamed imports at all here...