1extern crate proc_macro;
11
12use proc_macro::Delimiter;
13use proc_macro::Group;
14use proc_macro::Spacing;
15use proc_macro::TokenStream;
16use proc_macro::TokenTree;
17use std::iter::FromIterator;
18
19macro_rules! group {
20 ($delim:expr, $ts:expr) => {{
21 let _tt: TokenTree = ::proc_macro::Group::new($delim, $ts).into();
22 _tt
23 }};
24 ($delim:expr) => {
25 group!($delim, ::proc_macro::TokenStream::new())
26 };
27}
28
29macro_rules! ident {
30 ($name:expr, $span:expr) => {{
31 let _tt: TokenTree = ::proc_macro::Ident::new($name, $span).into();
32 _tt
33 }};
34 ($name:expr) => {
35 ident!($name, ::proc_macro::Span::call_site())
36 };
37}
38
39macro_rules! punct {
40 ($ch:expr, $spacing:expr) => {{
41 let _tt: TokenTree = ::proc_macro::Punct::new($ch, $spacing).into();
42 _tt
43 }};
44}
45
46macro_rules! token_stream {
47 ($($tt:expr,)*) => {
48 {
49 let _v: Vec<::proc_macro::TokenTree> = vec![$($tt),*];
50 let _ts: TokenStream = ::proc_macro::TokenStream::from_iter(_v.into_iter());
51 _ts
52 }
53 };
54 ($($tt:expr),*) => {
55 {
56 let _v: Vec<::proc_macro::TokenTree> = vec![$($tt),*];
57 let _ts: TokenStream = ::proc_macro::TokenStream::from_iter(_v.into_iter());
58 _ts
59 }
60 };
61}
62
63#[rustfmt::skip]
68fn protected_body(fn_body: Group) -> TokenTree {
69 group!(Delimiter::Brace, token_stream!(
70 group!(Delimiter::Brace, token_stream!(
71 punct!(':', Spacing::Joint),
72 punct!(':', Spacing::Alone),
73 ident!("qadapt"),
74 punct!(':', Spacing::Joint),
75 punct!(':', Spacing::Alone),
76 ident!("enter_protected"),
77 group!(Delimiter::Parenthesis)
78 )),
79 ident!("let"),
80 ident!("__ret__"),
81 punct!('=', Spacing::Alone),
82 fn_body.into(),
83 punct!(';', Spacing::Alone),
84 punct!('#', Spacing::Alone),
85 group!(Delimiter::Bracket, token_stream!(
88 ident!("allow"),
89 group!(Delimiter::Parenthesis, token_stream!(
90 ident!("unreachable_code")
91 ))
92 )),
93 group!(Delimiter::Brace, token_stream!(
94 group!(Delimiter::Brace, token_stream!(
95 punct!(':', Spacing::Joint),
96 punct!(':', Spacing::Alone),
97 ident!("qadapt"),
98 punct!(':', Spacing::Joint),
99 punct!(':', Spacing::Alone),
100 ident!("exit_protected"),
101 group!(Delimiter::Parenthesis)
102 )),
103 ident!("__ret__")
104 ))
105 ))
106}
107
108fn escape_return(ts: TokenStream) -> TokenStream {
111 let mut protected: Vec<TokenTree> = Vec::new();
112 let mut in_closure: bool = false;
113
114 let mut tt_iter = ts.into_iter();
115 while let Some(tt) = tt_iter.next() {
116 let tokens = match tt {
117 TokenTree::Group(ref g) if g.delimiter() == Delimiter::Brace && !in_closure => {
118 vec![group!(Delimiter::Brace, escape_return(g.stream()))]
119 }
120 TokenTree::Ident(ref i) if i.to_string() == "return" && !in_closure => vec![
121 group!(
122 Delimiter::Brace,
123 token_stream!(
124 punct!(':', Spacing::Joint),
125 punct!(':', Spacing::Alone),
126 ident!("qadapt"),
127 punct!(':', Spacing::Joint),
128 punct!(':', Spacing::Alone),
129 ident!("exit_protected"),
130 group!(Delimiter::Parenthesis)
131 )
132 ),
133 tt.clone(),
134 ],
135 TokenTree::Punct(ref p) if p.as_char() == '|' => {
136 in_closure = true;
137 vec![tt.clone()]
138 }
139 TokenTree::Punct(ref p) if p.as_char() == ';' => {
140 in_closure = false;
141 vec![tt.clone()]
142 }
143 t => vec![t],
144 };
145
146 protected.extend(tokens.into_iter());
147 }
148
149 TokenStream::from_iter(protected.into_iter())
150}
151
152#[proc_macro_attribute]
160#[deprecated(
161 since = "1.0.3",
162 note = "Please use the `alloc_counter` crate instead."
163)]
164pub fn no_alloc(_attr: TokenStream, item: TokenStream) -> TokenStream {
165 let mut protected_fn: Vec<TokenTree> = Vec::new();
166 let mut item_iter = item.into_iter();
167
168 let mut fn_body = None;
170 while let Some(tt) = item_iter.next() {
171 match tt {
172 TokenTree::Group(ref g) if g.delimiter() == Delimiter::Brace => {
173 fn_body = Some(Group::new(Delimiter::Brace, escape_return(g.stream())));
174 break;
175 }
176 tt => {
177 protected_fn.push(tt.clone());
178 }
179 }
180 }
181
182 protected_fn.push(protected_body(fn_body.as_ref().unwrap().clone()));
183
184 while let Some(tt) = item_iter.next() {
185 protected_fn.push(tt)
186 }
187
188 TokenStream::from_iter(protected_fn.into_iter())
189}