dtor_proc_macro/
lib.rs

1use std::iter::FromIterator;
2
3use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
4
5#[proc_macro_attribute]
6pub fn dtor(attribute: TokenStream, item: TokenStream) -> TokenStream {
7    generate("dtor", attribute, item)
8}
9
10/// Generates the equivalent of this Rust code as a TokenStream:
11/// 
12/// ```nocompile
13/// ::ctor::__support::ctor_parse!(#[ctor] fn foo() { ... });
14/// ::dtor::__support::dtor_parse!(#[dtor] fn foo() { ... });
15/// ```
16fn generate(macro_type: &str, attribute: TokenStream, item: TokenStream) -> TokenStream {
17    let mut inner = TokenStream::new();
18
19    #[cfg(feature = "used_linker")]
20    inner.extend([
21        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
22        TokenTree::Group(Group::new(Delimiter::Bracket, TokenStream::from_iter([
23            TokenTree::Ident(Ident::new("feature", Span::call_site())),
24            TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::from_iter([
25                TokenTree::Ident(Ident::new("used_linker", Span::call_site())),
26            ]))),
27        ]))),
28    ]);
29
30    #[cfg(feature = "__warn_on_missing_unsafe")]
31    inner.extend([
32        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
33        TokenTree::Group(Group::new(Delimiter::Bracket, TokenStream::from_iter([
34            TokenTree::Ident(Ident::new("feature", Span::call_site())),
35            TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::from_iter([
36                TokenTree::Ident(Ident::new("__warn_on_missing_unsafe", Span::call_site())),
37            ]))),
38        ]))),
39    ]);
40
41    if attribute.is_empty() {
42        // #[ctor]
43        inner.extend([
44            TokenTree::Punct(Punct::new('#', Spacing::Alone)),
45            TokenTree::Group(Group::new(Delimiter::Bracket, TokenStream::from_iter([
46                TokenTree::Ident(Ident::new(macro_type, Span::call_site())),
47            ]))),
48        ]);
49    } else {
50        inner.extend([
51            TokenTree::Punct(Punct::new('#', Spacing::Alone)),
52            TokenTree::Group(Group::new(Delimiter::Bracket, TokenStream::from_iter([
53                TokenTree::Ident(Ident::new(macro_type, Span::call_site())),
54                TokenTree::Group(Group::new(Delimiter::Parenthesis, attribute)),
55            ]))),
56        ]);
57    }
58
59    inner.extend(item);
60
61    TokenStream::from_iter([
62        TokenTree::Punct(Punct::new(':', Spacing::Joint)),
63        TokenTree::Punct(Punct::new(':', Spacing::Alone)),
64        TokenTree::Ident(Ident::new(macro_type, Span::call_site())),
65        TokenTree::Punct(Punct::new(':', Spacing::Joint)),
66        TokenTree::Punct(Punct::new(':', Spacing::Alone)),
67        TokenTree::Ident(Ident::new("__support", Span::call_site())),
68        TokenTree::Punct(Punct::new(':', Spacing::Joint)),
69        TokenTree::Punct(Punct::new(':', Spacing::Alone)),
70        TokenTree::Ident(Ident::new(&format!("{}_parse", macro_type), Span::call_site())),
71        TokenTree::Punct(Punct::new('!', Spacing::Alone)),
72        TokenTree::Group(Group::new(Delimiter::Parenthesis, inner)),
73        TokenTree::Punct(Punct::new(';', Spacing::Alone)),
74    ])
75}