use std::iter::FromIterator;
use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
#[proc_macro_attribute]
pub fn ctor(attribute: TokenStream, item: TokenStream) -> TokenStream {
generate("ctor", "ctor", attribute, item)
}
#[proc_macro_attribute]
pub fn dtor(attribute: TokenStream, item: TokenStream) -> TokenStream {
generate("dtor", "ctor", attribute, item)
}
fn generate(
macro_type: &str,
macro_crate: &str,
attribute: TokenStream,
item: TokenStream,
) -> TokenStream {
let mut inner = TokenStream::new();
let mut crate_path = None;
let mut tokens = attribute.clone().into_iter().peekable();
while let Some(token) = tokens.next() {
if let TokenTree::Ident(ident) = &token {
if ident.to_string() == "crate_path" {
if let Some(TokenTree::Punct(punct)) = tokens.next() {
if punct.as_char() == '=' {
let mut path = TokenStream::new();
while let Some(token) = tokens.peek() {
match token {
TokenTree::Punct(p) if p.as_char() == ',' => {
tokens.next();
break;
}
_ => {
path.extend(std::iter::once(tokens.next().unwrap()));
}
}
}
crate_path = Some(path);
break;
}
}
}
}
}
#[cfg(feature = "used_linker")]
inner.extend([
TokenTree::Punct(Punct::new('#', Spacing::Alone)),
TokenTree::Group(Group::new(
Delimiter::Bracket,
TokenStream::from_iter([
TokenTree::Ident(Ident::new("feature", Span::call_site())),
TokenTree::Group(Group::new(
Delimiter::Parenthesis,
TokenStream::from_iter([TokenTree::Ident(Ident::new(
"used_linker",
Span::call_site(),
))]),
)),
]),
)),
]);
#[cfg(feature = "__warn_on_missing_unsafe")]
inner.extend([
TokenTree::Punct(Punct::new('#', Spacing::Alone)),
TokenTree::Group(Group::new(
Delimiter::Bracket,
TokenStream::from_iter([
TokenTree::Ident(Ident::new("feature", Span::call_site())),
TokenTree::Group(Group::new(
Delimiter::Parenthesis,
TokenStream::from_iter([TokenTree::Ident(Ident::new(
"__warn_on_missing_unsafe",
Span::call_site(),
))]),
)),
]),
)),
]);
if attribute.is_empty() {
inner.extend([
TokenTree::Punct(Punct::new('#', Spacing::Alone)),
TokenTree::Group(Group::new(
Delimiter::Bracket,
TokenStream::from_iter([TokenTree::Ident(Ident::new(
macro_type,
Span::call_site(),
))]),
)),
]);
} else {
inner.extend([
TokenTree::Punct(Punct::new('#', Spacing::Alone)),
TokenTree::Group(Group::new(
Delimiter::Bracket,
TokenStream::from_iter([
TokenTree::Ident(Ident::new(macro_type, Span::call_site())),
TokenTree::Group(Group::new(Delimiter::Parenthesis, attribute)),
]),
)),
]);
}
inner.extend(item);
let mut invoke = crate_path.unwrap_or_else(|| {
TokenStream::from_iter([
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Ident(Ident::new(macro_crate, Span::call_site())),
])
});
invoke.extend([
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Ident(Ident::new("__support", Span::call_site())),
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Ident(Ident::new(
&format!("{}_parse", macro_crate),
Span::call_site(),
)),
TokenTree::Punct(Punct::new('!', Spacing::Alone)),
TokenTree::Group(Group::new(Delimiter::Parenthesis, inner)),
TokenTree::Punct(Punct::new(';', Spacing::Alone)),
]);
invoke
}