1use std::iter::FromIterator;
2
3use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
4
5#[proc_macro_attribute]
6pub fn ctor(attribute: TokenStream, item: TokenStream) -> TokenStream {
7 generate("ctor", "ctor", attribute, item)
8}
9
10#[proc_macro_attribute]
13pub fn dtor(attribute: TokenStream, item: TokenStream) -> TokenStream {
14 generate("dtor", "ctor", attribute, item)
15}
16
17fn generate(
24 macro_type: &str,
25 macro_crate: &str,
26 attribute: TokenStream,
27 item: TokenStream,
28) -> TokenStream {
29 let mut inner = TokenStream::new();
30
31 let mut crate_path = None;
33 let mut tokens = attribute.clone().into_iter().peekable();
34 while let Some(token) = tokens.next() {
35 if let TokenTree::Ident(ident) = &token {
36 if ident.to_string() == "crate_path" {
37 if let Some(TokenTree::Punct(punct)) = tokens.next() {
39 if punct.as_char() == '=' {
40 let mut path = TokenStream::new();
42 while let Some(token) = tokens.peek() {
43 match token {
44 TokenTree::Punct(p) if p.as_char() == ',' => {
45 tokens.next();
46 break;
47 }
48 _ => {
49 path.extend(std::iter::once(tokens.next().unwrap()));
50 }
51 }
52 }
53 crate_path = Some(path);
54 break;
55 }
56 }
57 }
58 }
59 }
60
61 #[cfg(feature = "used_linker")]
62 inner.extend([
63 TokenTree::Punct(Punct::new('#', Spacing::Alone)),
64 TokenTree::Group(Group::new(
65 Delimiter::Bracket,
66 TokenStream::from_iter([
67 TokenTree::Ident(Ident::new("feature", Span::call_site())),
68 TokenTree::Group(Group::new(
69 Delimiter::Parenthesis,
70 TokenStream::from_iter([TokenTree::Ident(Ident::new(
71 "used_linker",
72 Span::call_site(),
73 ))]),
74 )),
75 ]),
76 )),
77 ]);
78
79 #[cfg(feature = "__warn_on_missing_unsafe")]
80 inner.extend([
81 TokenTree::Punct(Punct::new('#', Spacing::Alone)),
82 TokenTree::Group(Group::new(
83 Delimiter::Bracket,
84 TokenStream::from_iter([
85 TokenTree::Ident(Ident::new("feature", Span::call_site())),
86 TokenTree::Group(Group::new(
87 Delimiter::Parenthesis,
88 TokenStream::from_iter([TokenTree::Ident(Ident::new(
89 "__warn_on_missing_unsafe",
90 Span::call_site(),
91 ))]),
92 )),
93 ]),
94 )),
95 ]);
96
97 if attribute.is_empty() {
98 inner.extend([
100 TokenTree::Punct(Punct::new('#', Spacing::Alone)),
101 TokenTree::Group(Group::new(
102 Delimiter::Bracket,
103 TokenStream::from_iter([TokenTree::Ident(Ident::new(
104 macro_type,
105 Span::call_site(),
106 ))]),
107 )),
108 ]);
109 } else {
110 inner.extend([
111 TokenTree::Punct(Punct::new('#', Spacing::Alone)),
112 TokenTree::Group(Group::new(
113 Delimiter::Bracket,
114 TokenStream::from_iter([
115 TokenTree::Ident(Ident::new(macro_type, Span::call_site())),
116 TokenTree::Group(Group::new(Delimiter::Parenthesis, attribute)),
117 ]),
118 )),
119 ]);
120 }
121
122 inner.extend(item);
123
124 let mut invoke = crate_path.unwrap_or_else(|| {
125 TokenStream::from_iter([
126 TokenTree::Punct(Punct::new(':', Spacing::Joint)),
127 TokenTree::Punct(Punct::new(':', Spacing::Alone)),
128 TokenTree::Ident(Ident::new(macro_crate, Span::call_site())),
129 ])
130 });
131
132 invoke.extend([
133 TokenTree::Punct(Punct::new(':', Spacing::Joint)),
134 TokenTree::Punct(Punct::new(':', Spacing::Alone)),
135 TokenTree::Ident(Ident::new("__support", Span::call_site())),
136 TokenTree::Punct(Punct::new(':', Spacing::Joint)),
137 TokenTree::Punct(Punct::new(':', Spacing::Alone)),
138 TokenTree::Ident(Ident::new(
139 &format!("{}_parse", macro_type),
140 Span::call_site(),
141 )),
142 TokenTree::Punct(Punct::new('!', Spacing::Alone)),
143 TokenTree::Group(Group::new(Delimiter::Parenthesis, inner)),
144 TokenTree::Punct(Punct::new(';', Spacing::Alone)),
145 ]);
146
147 invoke
148}