add support for raw parameters

#[export]
    fn foo(#[raw] this: Value) -> Result<(), Error>;

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2020-11-24 10:36:03 +01:00
parent 29e61fa65e
commit 0cdb12e277
2 changed files with 44 additions and 20 deletions

View File

@ -14,19 +14,18 @@ pub struct XSub {
pub fn handle_function( pub fn handle_function(
attr: FunctionAttrs, attr: FunctionAttrs,
func: syn::ItemFn, mut func: syn::ItemFn,
mangled_package_name: Option<&str>, mangled_package_name: Option<&str>,
) -> Result<XSub, Error> { ) -> Result<XSub, Error> {
let sig = &func.sig; if !func.sig.generics.params.is_empty() {
if !sig.generics.params.is_empty() { bail!(&func.sig.generics => "generic functions cannot be exported as xsubs");
bail!(&sig.generics => "generic functions cannot be exported as xsubs");
} }
if sig.asyncness.is_some() { if func.sig.asyncness.is_some() {
bail!(&sig.asyncness => "async fns cannot be exported as xsubs"); bail!(&func.sig.asyncness => "async fns cannot be exported as xsubs");
} }
let name = &sig.ident; let name = func.sig.ident.clone();
let xs_name = attr.xs_name.unwrap_or_else(|| match mangled_package_name { let xs_name = attr.xs_name.unwrap_or_else(|| match mangled_package_name {
None => Ident::new(&format!("xs_{}", name), name.span()), None => Ident::new(&format!("xs_{}", name), name.span()),
Some(prefix) => Ident::new(&format!("xs_{}_{}", prefix, name), name.span()), Some(prefix) => Ident::new(&format!("xs_{}_{}", prefix, name), name.span()),
@ -36,10 +35,22 @@ pub fn handle_function(
let mut extract_arguments = TokenStream::new(); let mut extract_arguments = TokenStream::new();
let mut deserialized_arguments = TokenStream::new(); let mut deserialized_arguments = TokenStream::new();
let mut passed_arguments = TokenStream::new(); let mut passed_arguments = TokenStream::new();
for arg in &sig.inputs { for arg in &mut func.sig.inputs {
let mut raw_arg = false;
let pat_ty = match arg { let pat_ty = match arg {
syn::FnArg::Receiver(_) => bail!(arg => "cannot export self-taking methods as xsubs"), syn::FnArg::Receiver(_) => bail!(arg => "cannot export self-taking methods as xsubs"),
syn::FnArg::Typed(pt) => pt, syn::FnArg::Typed(ref mut pt) => {
pt.attrs.retain(|attr| {
if attr.path.is_ident("raw") {
raw_arg = true;
false
} else {
true
}
});
&*pt
}
}; };
let arg_name = match &*pat_ty.pat { let arg_name = match &*pat_ty.pat {
@ -74,16 +85,22 @@ pub fn handle_function(
}; };
}); });
deserialized_arguments.extend(quote! { if raw_arg {
let #deserialized_name: #arg_type = match ::perlmod::from_value(#extracted_name) { deserialized_arguments.extend(quote! {
Ok(data) => data, let #deserialized_name = #extracted_name;
Err(err) => { });
return Err(::perlmod::Value::new_string(&err.to_string()) } else {
.into_mortal() deserialized_arguments.extend(quote! {
.into_raw()); let #deserialized_name: #arg_type = match ::perlmod::from_value(#extracted_name) {
} Ok(data) => data,
}; Err(err) => {
}); return Err(::perlmod::Value::new_string(&err.to_string())
.into_mortal()
.into_raw());
}
};
});
}
if passed_arguments.is_empty() { if passed_arguments.is_empty() {
passed_arguments.extend(quote! { #deserialized_name }); passed_arguments.extend(quote! { #deserialized_name });
@ -96,7 +113,7 @@ pub fn handle_function(
&format!( &format!(
"too many parameters for function '{}', (expected {})", "too many parameters for function '{}', (expected {})",
name, name,
sig.inputs.len() func.sig.inputs.len()
), ),
Span::call_site(), Span::call_site(),
); );

View File

@ -12,4 +12,11 @@ mod export {
Ok(hash) Ok(hash)
//Ok(this.bless("RSPM::Bless")?) //Ok(this.bless("RSPM::Bless")?)
} }
#[export]
fn something(#[raw] value: Value) -> Result<(), Error> {
println!("Called something!");
Ok(())
}
} }