extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn ctor(_attribute: TokenStream, function: TokenStream) -> TokenStream {
let function: syn::ItemFn = syn::parse_macro_input!(function);
validate_item("ctor", &function);
let syn::ItemFn {
ident,
unsafety,
constness,
abi,
block,
attrs,
..
} = function;
let output = quote!(
#[used]
#[cfg_attr(target_os = "linux", link_section = ".ctors")]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
#[cfg_attr(windows, link_section = ".CRT$XCU")]
#(#attrs)*
static #ident
:
#unsafety extern #abi #constness fn() =
{ #unsafety extern #abi #constness fn #ident() #block; #ident }
;
);
output.into()
}
#[proc_macro_attribute]
pub fn dtor(_attribute: TokenStream, function: TokenStream) -> TokenStream {
let function: syn::ItemFn = syn::parse_macro_input!(function);
validate_item("dtor", &function);
let syn::ItemFn {
ident,
unsafety,
constness,
abi,
block,
attrs,
..
} = function;
let output = quote!(
mod #ident {
use super::*;
extern "C" {
fn atexit(cb: #unsafety extern fn());
}
#[used]
#[cfg_attr(target_os = "linux", link_section = ".ctors")]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
#[cfg_attr(windows, link_section = ".CRT$XCU")]
#(#attrs)*
static __dtor_export
:
unsafe extern #abi #constness fn() =
{
#unsafety extern #abi #constness fn #ident() #block;
unsafe extern fn __dtor_atexit() {
atexit(#ident);
};
__dtor_atexit
};
}
);
output.into()
}
fn validate_item(typ: &str, item: &syn::ItemFn) {
let syn::ItemFn { vis, decl, .. } = item;
match vis {
syn::Visibility::Inherited => {}
_ => panic!("#[{}] methods must not have visibility modifiers", typ),
}
if decl.inputs.len() > 0 {
panic!("#[{}] methods may not have parameters", typ);
}
match decl.output {
syn::ReturnType::Default => {}
_ => panic!("#[{}] methods must not have return types", typ),
}
}