]>
git.proxmox.com Git - perlmod.git/blob - perlmod-macro/src/attribs.rs
1 use proc_macro2
::{Ident, Span}
;
3 use syn
::AttributeArgs
;
6 pub struct ModuleAttrs
{
7 pub package_name
: String
,
8 pub file_name
: Option
<String
>,
9 pub lib_name
: Option
<String
>,
10 pub write
: Option
<bool
>,
13 fn is_ident_check_dup
<T
>(path
: &syn
::Path
, var
: &Option
<T
>, what
: &'
static str) -> bool
{
14 if path
.is_ident(what
) {
16 error
!(path
=> "found multiple '{}' attributes", what
);
24 impl TryFrom
<AttributeArgs
> for ModuleAttrs
{
27 fn try_from(args
: AttributeArgs
) -> Result
<Self, Self::Error
> {
28 let mut package_name
= None
;
29 let mut file_name
= None
;
30 let mut lib_name
= None
;
35 syn
::NestedMeta
::Meta(syn
::Meta
::NameValue(syn
::MetaNameValue
{
37 lit
: syn
::Lit
::Str(litstr
),
40 if is_ident_check_dup(&path
, &package_name
, "name") {
41 package_name
= Some(expand_env_vars(&litstr
)?
);
42 } else if is_ident_check_dup(&path
, &file_name
, "file") {
43 file_name
= Some(expand_env_vars(&litstr
)?
);
44 } else if is_ident_check_dup(&path
, &lib_name
, "lib") {
45 lib_name
= Some(expand_env_vars(&litstr
)?
);
47 error
!(path
=> "unknown argument");
50 syn
::NestedMeta
::Meta(syn
::Meta
::NameValue(syn
::MetaNameValue
{
52 lit
: syn
::Lit
::Bool(litbool
),
55 if is_ident_check_dup(&path
, &write
, "write") {
56 write
= Some(litbool
.value());
58 error
!(path
=> "unknown argument");
61 _
=> error
!(Span
::call_site(), "unexpected attribute argument"),
65 let package_name
= package_name
66 .ok_or_else(|| format_err
!(Span
::call_site(), "missing 'package' argument"))?
;
77 fn expand_env_vars(lit_str
: &syn
::LitStr
) -> Result
<String
, Error
> {
78 let input
= lit_str
.value();
79 let mut expanded
= String
::with_capacity(input
.len());
81 let mut input
= input
.as_str();
83 let dollar
= match input
.find("${") {
86 expanded
.push_str(input
);
91 expanded
.push_str(&input
[..dollar
]);
92 input
= &input
[(dollar
+ 2)..];
94 let end
= input
.find('
}'
).ok_or_else(
95 || format_err
!(lit_str
=> "missing end of environment variable expansion"),
98 let var_name
= &input
[..end
];
99 input
= &input
[(end
+ 1)..];
101 let var
= std
::env
::var(var_name
).map_err(|err
| {
102 format_err
!(lit_str
=> "failed to expand environment variable {:?}: {}", var_name
, err
)
104 expanded
.push_str(&var
);
111 pub fn mangle_package_name(&self) -> String
{
112 let mut out
= String
::with_capacity(self.package_name
.len());
113 for ch
in self.package_name
.chars() {
114 if ch
.is_ascii_alphabetic() || ch
.is_ascii_digit() {
125 pub struct FunctionAttrs
{
126 pub perl_name
: Option
<Ident
>,
127 pub xs_name
: Option
<Ident
>,
128 pub raw_return
: bool
,
129 pub cv_variable
: Option
<Ident
>,
130 pub prototype
: Option
<String
>,
131 pub serialize_error
: bool
,
135 impl TryFrom
<AttributeArgs
> for FunctionAttrs
{
138 fn try_from(args
: AttributeArgs
) -> Result
<Self, Self::Error
> {
139 let mut attrs
= FunctionAttrs
::default();
143 syn
::NestedMeta
::Meta(syn
::Meta
::NameValue(syn
::MetaNameValue
{
145 lit
: syn
::Lit
::Str(litstr
),
148 if is_ident_check_dup(&path
, &attrs
.xs_name
, "xs_name") {
149 attrs
.xs_name
= Some(Ident
::new(&litstr
.value(), litstr
.span()));
150 } else if is_ident_check_dup(&path
, &attrs
.perl_name
, "name") {
151 attrs
.perl_name
= Some(Ident
::new(&litstr
.value(), litstr
.span()));
152 } else if is_ident_check_dup(&path
, &attrs
.prototype
, "prototype") {
153 attrs
.prototype
= Some(litstr
.value());
155 error
!(path
=> "unknown argument");
159 syn
::NestedMeta
::Meta(syn
::Meta
::Path(path
)) => {
160 if path
.is_ident("raw_return") {
161 attrs
.raw_return
= true;
162 } else if path
.is_ident("serialize_error") {
163 attrs
.serialize_error
= true;
164 } else if path
.is_ident("errno") {
167 error
!(path
=> "unknown attribute");
170 _
=> error
!(Span
::call_site(), "unexpected attribute argument"),