pub struct FunctionAttrs {
pub xs_name: Option<Ident>,
+ pub raw_return: bool,
}
impl TryFrom<AttributeArgs> for FunctionAttrs {
fn try_from(args: AttributeArgs) -> Result<Self, Self::Error> {
let mut xs_name = None;
+ let mut raw_return = false;
for arg in args {
match arg {
bail!(path => "unknown argument");
}
}
+ syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
+ if path.is_ident("raw_return") {
+ raw_return = true;
+ } else {
+ bail!(path => "unknown attribute");
+ }
+ }
_ => bail!(Span::call_site(), "unexpected attribute argument"),
}
}
- Ok(Self { xs_name })
+ Ok(Self {
+ xs_name,
+ raw_return,
+ })
}
}
use anyhow::Error;
-use proc_macro2::{Ident, TokenStream, Span};
+use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
func: syn::ItemFn,
mangled_package_name: Option<&str>,
) -> Result<XSub, Error> {
- //let vis = core::mem::replace(&mut func.vis, syn::Visibility::Inherited);
- //if let syn::Visibility::Public(_) = vis {
- // // ok
- //} else {
- // bail!(func.sig.fn_token => "only public functions can be exported as xsubs");
- //}
-
let sig = &func.sig;
if !sig.generics.params.is_empty() {
bail!(&sig.generics => "generic functions cannot be exported as xsubs");
}
let name = &sig.ident;
- let xs_name = attr
- .xs_name
- .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()),
- });
+ let xs_name = attr.xs_name.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()),
+ });
let impl_xs_name = Ident::new(&format!("impl_xs_{}", name), name.span());
let mut extract_arguments = TokenStream::new();
}
let too_many_args_error = syn::LitStr::new(
- &format!("too many parameters for function '{}', (expected {})", name, sig.inputs.len()),
+ &format!(
+ "too many parameters for function '{}', (expected {})",
+ name,
+ sig.inputs.len()
+ ),
Span::call_site(),
);
+ let handle_return = if attr.raw_return {
+ quote! {
+ Ok(result.into_mortal().into_raw())
+ }
+ } else {
+ quote! {
+ match ::perlmod::to_value(&result) {
+ Ok(value) => Ok(value.into_mortal().into_raw()),
+ Err(err) => Err(::perlmod::Value::new_string(&err.to_string())
+ .into_mortal()
+ .into_raw()),
+ }
+ }
+ };
+
let tokens = quote! {
#func
}
};
- match ::perlmod::to_value(&result) {
- Ok(value) => Ok(value.into_mortal().into_raw()),
- Err(err) => Err(::perlmod::Value::new_string(&err.to_string())
- .into_mortal()
- .into_raw()),
- }
+ #handle_return
}
};
use proc_macro2::TokenStream;
use quote::quote;
-use syn::parse::Parser;
use syn::punctuated::Punctuated;
use syn::{AttributeArgs, Token};
--- /dev/null
+#[perlmod::package(name = "RSPM::Bless", lib = "perlmod_test")]
+mod export {
+ use anyhow::Error;
+
+ use perlmod::Value;
+
+ #[export(raw_return)]
+ fn new() -> Result<Value, Error> {
+ let hash = Value::from(perlmod::hash::Hash::new());
+ let hash = Value::new_ref(&hash);
+ let hash = hash.bless("RSPM::Bless")?;
+ Ok(hash)
+ //Ok(this.bless("RSPM::Bless")?)
+ }
+}
/// This is possible on stable rust with some 1.3x already.
mod pkgstable;
+
+/// A test for blessed values.
+mod bless;
Value::Reference(unsafe { Scalar::from_raw_move(ffi::RSPL_newRV_inc(value.sv())) })
}
- /// Bless a value into a package. This turns the value into a reference and forwards to
- /// [`Value::bless_ref`].
- pub fn bless_value(&self, package: &str) -> Result<Value, Error> {
- self.clone_ref().bless_ref(package)
- }
-
/// Bless a reference into a package. The `Value` must be a reference.
- pub fn bless_ref(&self, package: &str) -> Result<Value, Error> {
- let value = match self {
- Value::Reference(v) => v,
- _ => Error::fail("trying to bless a non-reference")?,
- };
-
+ pub fn bless(&self, package: &str) -> Result<Value, Error> {
let pkgsv = Scalar::new_string(package);
let stash = unsafe { ffi::RSPL_gv_stashsv(pkgsv.sv(), 0) };
if stash.is_null() {
return Err(Error(format!("failed to find package {:?}", package)));
}
- let value = unsafe { ffi::RSPL_sv_bless(value.sv(), stash) };
+ let value = unsafe { ffi::RSPL_sv_bless(self.sv(), stash) };
if value.is_null() {
return Err(Error(format!(
"failed to bless value into package {:?}",
)));
}
- Ok(Value::Reference(unsafe { Scalar::from_raw_move(value) }))
+ Ok(Value::Reference(unsafe { Scalar::from_raw_ref(value) }))
}
/// Take over a raw `SV` value, assuming that we then own a reference to it.