perlmod/perlmod-macro/src/attribs.rs
Wolfgang Bumiller 2991a46a31 fix #[export(name=...)], drop deprecated make_package
The `make_package` macro is tedious to use. We now simply
depend on new-enough rustc for `package` to work.

The change to #[export] allows writing:

    #[export(name = "DESTROY")]
    fn destroy(#[raw] this: Value) { ... }

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
2020-11-25 14:35:34 +01:00

109 lines
3.2 KiB
Rust

use std::convert::TryFrom;
use proc_macro2::{Ident, Span};
use syn::AttributeArgs;
pub struct ModuleAttrs {
pub package_name: String,
pub file_name: Option<String>,
pub lib_name: Option<String>,
}
impl TryFrom<AttributeArgs> for ModuleAttrs {
type Error = syn::Error;
fn try_from(args: AttributeArgs) -> Result<Self, Self::Error> {
let mut package_name = None;
let mut file_name = None;
let mut lib_name = None;
for arg in args {
match arg {
syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
path,
lit: syn::Lit::Str(litstr),
..
})) => {
if path.is_ident("name") {
package_name = Some(litstr.value());
} else if path.is_ident("file") {
file_name = Some(litstr.value());
} else if path.is_ident("lib") {
lib_name = Some(litstr.value());
} else {
bail!(path => "unknown argument");
}
}
_ => bail!(Span::call_site(), "unexpected attribute argument"),
}
}
let package_name = package_name
.ok_or_else(|| format_err!(Span::call_site(), "missing 'package' argument"))?;
Ok(Self {
package_name,
file_name,
lib_name,
})
}
}
impl ModuleAttrs {
pub fn mangle_package_name(&self) -> String {
let mut out = String::with_capacity(self.package_name.len());
for ch in self.package_name.chars() {
if ch.is_ascii_alphabetic() || ch.is_ascii_digit() {
out.push(ch);
} else {
out.push('_');
}
}
out
}
}
#[derive(Default)]
pub struct FunctionAttrs {
pub perl_name: Option<Ident>,
pub xs_name: Option<Ident>,
pub raw_return: bool,
}
impl TryFrom<AttributeArgs> for FunctionAttrs {
type Error = syn::Error;
fn try_from(args: AttributeArgs) -> Result<Self, Self::Error> {
let mut attrs = FunctionAttrs::default();
for arg in args {
match arg {
syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
path,
lit: syn::Lit::Str(litstr),
..
})) => {
if path.is_ident("xs_name") {
attrs.xs_name = Some(Ident::new(&litstr.value(), litstr.span()));
} else if path.is_ident("name") {
attrs.perl_name = Some(Ident::new(&litstr.value(), litstr.span()));
} else {
bail!(path => "unknown argument");
}
}
syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
if path.is_ident("raw_return") {
attrs.raw_return = true;
} else {
bail!(path => "unknown attribute");
}
}
_ => bail!(Span::call_site(), "unexpected attribute argument"),
}
}
Ok(attrs)
}
}