dtor_proc_macro/
lib.rs
1#![doc = include_str!("../README.md")]
2
3use std::iter::FromIterator;
4
5use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
6
7#[allow(missing_docs)]
8#[proc_macro_attribute]
9pub fn dtor(attribute: TokenStream, item: TokenStream) -> TokenStream {
10 generate("dtor", "dtor", attribute, item)
11}
12
13#[allow(missing_docs)]
14#[proc_macro_attribute]
15pub fn __dtor_from_ctor(attribute: TokenStream, item: TokenStream) -> TokenStream {
16 generate("ctor", "dtor", attribute, item)
17}
18
19#[allow(unknown_lints, tail_expr_drop_order)]
26fn generate(
27 macro_crate: &str,
28 macro_type: &str,
29 attribute: TokenStream,
30 item: TokenStream,
31) -> TokenStream {
32 let mut inner = TokenStream::new();
33
34 let mut crate_path = None;
36 let mut tokens = attribute.clone().into_iter().peekable();
37
38 while let Some(token) = tokens.next() {
39 if let TokenTree::Ident(ident) = &token {
40 if ident.to_string() == "crate_path" {
41 if let Some(TokenTree::Punct(punct)) = tokens.next() {
43 if punct.as_char() == '=' {
44 let mut path = TokenStream::new();
46 while let Some(token) = tokens.peek() {
47 match token {
48 TokenTree::Punct(p) if p.as_char() == ',' => {
49 tokens.next();
50 break;
51 }
52 _ => {
53 path.extend(std::iter::once(tokens.next().unwrap()));
54 }
55 }
56 }
57 crate_path = Some(path);
58 break;
59 }
60 }
61 }
62 }
63 }
64
65 if attribute.is_empty() {
66 inner.extend([
68 TokenTree::Punct(Punct::new('#', Spacing::Alone)),
69 TokenTree::Group(Group::new(
70 Delimiter::Bracket,
71 TokenStream::from_iter([TokenTree::Ident(Ident::new(
72 macro_type,
73 Span::call_site(),
74 ))]),
75 )),
76 ]);
77 } else {
78 inner.extend([
79 TokenTree::Punct(Punct::new('#', Spacing::Alone)),
80 TokenTree::Group(Group::new(
81 Delimiter::Bracket,
82 TokenStream::from_iter([
83 TokenTree::Ident(Ident::new(macro_type, Span::call_site())),
84 TokenTree::Group(Group::new(Delimiter::Parenthesis, attribute)),
85 ]),
86 )),
87 ]);
88 }
89
90 inner.extend(item);
91
92 let mut invoke = crate_path.unwrap_or_else(|| {
93 TokenStream::from_iter([
94 TokenTree::Punct(Punct::new(':', Spacing::Joint)),
95 TokenTree::Punct(Punct::new(':', Spacing::Alone)),
96 TokenTree::Ident(Ident::new(macro_crate, Span::call_site())),
97 ])
98 });
99
100 invoke.extend([
101 TokenTree::Punct(Punct::new(':', Spacing::Joint)),
102 TokenTree::Punct(Punct::new(':', Spacing::Alone)),
103 TokenTree::Ident(Ident::new("__support", Span::call_site())),
104 TokenTree::Punct(Punct::new(':', Spacing::Joint)),
105 TokenTree::Punct(Punct::new(':', Spacing::Alone)),
106 TokenTree::Ident(Ident::new(
107 &format!("{}_parse", macro_type),
108 Span::call_site(),
109 )),
110 TokenTree::Punct(Punct::new('!', Spacing::Alone)),
111 TokenTree::Group(Group::new(Delimiter::Parenthesis, inner)),
112 TokenTree::Punct(Punct::new(';', Spacing::Alone)),
113 ]);
114
115 invoke
116}