#![recursion_limit = "256"]
extern crate proc_macro;
use std::iter::FromIterator;
use proc_macro::*;
#[rustfmt::skip]
mod gen;
#[proc_macro_attribute]
pub fn ctor(_attribute: TokenStream, item: TokenStream) -> TokenStream {
fn identify_item(item: TokenStream) -> (String, String) {
let mut ctor_type = String::new();
for token in item {
if let TokenTree::Ident(ident) = token {
let ident = ident.to_string();
if !ctor_type.is_empty() {
return (ident, ctor_type);
}
if ident == "fn" || ident == "static" {
ctor_type = ident;
}
}
}
panic!("#[ctor] may only be applied to `fn` or `static` items");
}
let (name, ctor_type) = identify_item(item.clone());
generate(&name, &ctor_type, item)
}
#[proc_macro_attribute]
pub fn dtor(_attribute: TokenStream, item: TokenStream) -> TokenStream {
fn identify_item(item: TokenStream) -> (String, String) {
let mut ctor_type = String::new();
for token in item {
if let TokenTree::Ident(ident) = token {
let ident = ident.to_string();
if !ctor_type.is_empty() {
return (ident, ctor_type);
}
if ident == "fn" {
"dtor".clone_into(&mut ctor_type);
}
}
}
panic!("#[dtor] may only be applied to `fn`items");
}
let (name, ctor_type) = identify_item(item.clone());
generate(&name, &ctor_type, item)
}
fn generate(name: &str, ctor_type: &str, item: TokenStream) -> TokenStream {
use proc_macro::TokenTree as T;
let support_name = format!("__rust_ctor__{name}");
let macros_name = format!("__rust_ctor_macros_{name}");
TokenStream::from_iter([
T::Ident(Ident::new(¯os_name, Span::call_site())),
T::Punct(Punct::new(':', Spacing::Joint)),
T::Punct(Punct::new(':', Spacing::Alone)),
T::Ident(Ident::new("ctor_impl", Span::call_site())),
T::Punct(Punct::new('!', Spacing::Alone)),
T::Group(Group::new(
Delimiter::Parenthesis,
TokenStream::from_iter([
T::Ident(Ident::new(ctor_type, Span::call_site())),
T::Ident(Ident::new("macros", Span::call_site())),
T::Punct(Punct::new('=', Spacing::Alone)),
T::Ident(Ident::new(¯os_name, Span::call_site())),
T::Ident(Ident::new("name", Span::call_site())),
T::Punct(Punct::new('=', Spacing::Alone)),
T::Ident(Ident::new(&support_name, Span::call_site())),
T::Ident(Ident::new("used", Span::call_site())),
T::Punct(Punct::new('=', Spacing::Alone)),
T::Ident(Ident::new("used", Span::call_site())),
#[cfg(feature = "used_linker")]
T::Group(Group::new(
Delimiter::Parenthesis,
TokenStream::from_iter([T::Ident(Ident::new("linker", Span::call_site()))]),
)),
T::Ident(Ident::new("item", Span::call_site())),
T::Punct(Punct::new('=', Spacing::Alone)),
T::Group(Group::new(Delimiter::Brace, item)),
]),
)),
T::Punct(Punct::new(';', Spacing::Alone)),
T::Punct(Punct::new('#', Spacing::Alone)),
T::Group(Group::new(
Delimiter::Bracket,
TokenStream::from_iter([
T::Ident(Ident::new("allow", Span::call_site())),
T::Group(Group::new(
Delimiter::Parenthesis,
TokenStream::from_iter([T::Ident(Ident::new(
"non_snake_case",
Span::call_site(),
))]),
)),
]),
)),
T::Ident(Ident::new("mod", Span::call_site())),
T::Ident(Ident::new(¯os_name, Span::call_site())),
T::Group(Group::new(
Delimiter::Brace,
TokenStream::from_iter([gen::ctor(), gen::ctor_raw()]),
)),
])
}