1use std::cell::RefCell;
4use std::marker::PhantomData;
5
6use super::*;
7
8pub(crate) struct TokenStream {
9 handle: handle::Handle,
10}
11
12impl !Send for TokenStream {}
13impl !Sync for TokenStream {}
14
15impl Drop for TokenStream {
17 fn drop(&mut self) {
18 Methods::ts_drop(TokenStream { handle: self.handle });
19 }
20}
21
22impl<S> Encode<S> for TokenStream {
23 #[inline]
24 fn encode(self, w: &mut Buffer, s: &mut S) {
25 mem::ManuallyDrop::new(self).handle.encode(w, s);
26 }
27}
28
29impl<S> Encode<S> for &TokenStream {
30 #[inline]
31 fn encode(self, w: &mut Buffer, s: &mut S) {
32 self.handle.encode(w, s);
33 }
34}
35
36impl<S> Decode<'_, '_, S> for TokenStream {
37 #[inline]
38 fn decode(r: &mut &[u8], s: &mut S) -> Self {
39 TokenStream { handle: handle::Handle::decode(r, s) }
40 }
41}
42
43impl Encode<()> for crate::TokenStream {
44 #[inline]
45 fn encode(self, w: &mut Buffer, s: &mut ()) {
46 self.0.encode(w, s)
47 }
48}
49
50impl Decode<'_, '_, ()> for crate::TokenStream {
51 #[inline]
52 fn decode(r: &mut &[u8], s: &mut ()) -> Self {
53 crate::TokenStream(Some(Decode::decode(r, s)))
54 }
55}
56
57#[derive(Copy, Clone, PartialEq, Eq, Hash)]
58pub(crate) struct Span {
59 handle: handle::Handle,
60}
61
62impl !Send for Span {}
63impl !Sync for Span {}
64
65impl<S> Encode<S> for Span {
66 #[inline]
67 fn encode(self, w: &mut Buffer, s: &mut S) {
68 self.handle.encode(w, s);
69 }
70}
71
72impl<S> Decode<'_, '_, S> for Span {
73 #[inline]
74 fn decode(r: &mut &[u8], s: &mut S) -> Self {
75 Span { handle: handle::Handle::decode(r, s) }
76 }
77}
78
79impl Clone for TokenStream {
80 fn clone(&self) -> Self {
81 Methods::ts_clone(self)
82 }
83}
84
85impl Span {
86 pub(crate) fn def_site() -> Span {
87 Bridge::with(|bridge| bridge.globals.def_site)
88 }
89
90 pub(crate) fn call_site() -> Span {
91 Bridge::with(|bridge| bridge.globals.call_site)
92 }
93
94 pub(crate) fn mixed_site() -> Span {
95 Bridge::with(|bridge| bridge.globals.mixed_site)
96 }
97}
98
99impl fmt::Debug for Span {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 f.write_str(&Methods::span_debug(*self))
102 }
103}
104
105pub(crate) use super::Methods;
106pub(crate) use super::symbol::Symbol;
107
108macro_rules! define_client_side {
109 (
110 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
111 ) => {
112 impl Methods {
113 $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? {
114 Bridge::with(|bridge| {
115 let mut buf = bridge.cached_buffer.take();
116
117 buf.clear();
118 ApiTags::$method.encode(&mut buf, &mut ());
119 $($arg.encode(&mut buf, &mut ());)*
120
121 buf = bridge.dispatch.call(buf);
122
123 let r = Result::<_, PanicMessage>::decode(&mut &buf[..], &mut ());
124
125 bridge.cached_buffer = buf;
126
127 r.unwrap_or_else(|e| panic::resume_unwind(e.into()))
128 })
129 })*
130 }
131 }
132}
133with_api!(define_client_side, TokenStream, Span, Symbol);
134
135struct Bridge<'a> {
136 cached_buffer: Buffer,
139
140 dispatch: closure::Closure<'a>,
142
143 globals: ExpnGlobals<Span>,
145}
146
147impl<'a> !Send for Bridge<'a> {}
148impl<'a> !Sync for Bridge<'a> {}
149
150#[allow(unsafe_code)]
151mod state {
152 use std::cell::{Cell, RefCell};
153 use std::ptr;
154
155 use super::Bridge;
156
157 thread_local! {
158 static BRIDGE_STATE: Cell<*const ()> = const { Cell::new(ptr::null()) };
159 }
160
161 pub(super) fn set<'bridge, R>(state: &RefCell<Bridge<'bridge>>, f: impl FnOnce() -> R) -> R {
162 struct RestoreOnDrop(*const ());
163 impl Drop for RestoreOnDrop {
164 fn drop(&mut self) {
165 BRIDGE_STATE.set(self.0);
166 }
167 }
168
169 let inner = ptr::from_ref(state).cast();
170 let outer = BRIDGE_STATE.replace(inner);
171 let _restore = RestoreOnDrop(outer);
172
173 f()
174 }
175
176 pub(super) fn with<R>(
177 f: impl for<'bridge> FnOnce(Option<&RefCell<Bridge<'bridge>>>) -> R,
178 ) -> R {
179 let state = BRIDGE_STATE.get();
180 let bridge = unsafe { state.cast::<RefCell<Bridge<'static>>>().as_ref() };
188 f(bridge)
189 }
190}
191
192impl Bridge<'_> {
193 fn with<R>(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R {
194 state::with(|state| {
195 let bridge = state.expect("procedural macro API is used outside of a procedural macro");
196 let mut bridge = bridge
197 .try_borrow_mut()
198 .expect("procedural macro API is used while it's already in use");
199 f(&mut bridge)
200 })
201 }
202}
203
204pub(crate) fn is_available() -> bool {
205 state::with(|s| s.is_some())
206}
207
208#[repr(C)]
220pub struct Client<I, O> {
221 pub(super) run: extern "C" fn(BridgeConfig<'_>) -> Buffer,
222
223 pub(super) _marker: PhantomData<fn(I) -> O>,
224}
225
226impl<I, O> Copy for Client<I, O> {}
227impl<I, O> Clone for Client<I, O> {
228 fn clone(&self) -> Self {
229 *self
230 }
231}
232
233fn maybe_install_panic_hook(force_show_panics: bool) {
234 static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
237 HIDE_PANICS_DURING_EXPANSION.call_once(|| {
238 let prev = panic::take_hook();
239 panic::set_hook(Box::new(move |info| {
240 if force_show_panics || !is_available() || !info.can_unwind() {
245 prev(info)
246 }
247 }));
248 });
249}
250
251fn run_client<A: for<'a, 's> Decode<'a, 's, ()>>(
254 config: BridgeConfig<'_>,
255 f: impl FnOnce(A) -> crate::TokenStream,
256) -> Buffer {
257 let BridgeConfig { input: mut buf, dispatch, force_show_panics, .. } = config;
258
259 let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
260 maybe_install_panic_hook(force_show_panics);
261
262 Symbol::invalidate_all();
264
265 let reader = &mut &buf[..];
266 let (globals, input) = <(ExpnGlobals<Span>, A)>::decode(reader, &mut ());
267
268 let state = RefCell::new(Bridge { cached_buffer: buf.take(), dispatch, globals });
270
271 let output = state::set(&state, || f(input));
272
273 buf = RefCell::into_inner(state).cached_buffer;
275
276 output
277 }));
278
279 buf.clear();
281 res.map_err(PanicMessage::from).encode(&mut buf, &mut ());
282
283 Symbol::invalidate_all();
286 buf
287}
288
289impl Client<crate::TokenStream, crate::TokenStream> {
290 pub const fn expand1(f: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy) -> Self {
291 Client {
292 run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| {
293 run_client(bridge, |input| f(input))
294 }),
295 _marker: PhantomData,
296 }
297 }
298}
299
300impl Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream> {
301 pub const fn expand2(
302 f: impl Fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream + Copy,
303 ) -> Self {
304 Client {
305 run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| {
306 run_client(bridge, |(input, input2)| f(input, input2))
307 }),
308 _marker: PhantomData,
309 }
310 }
311}
312
313#[repr(C)]
314#[derive(Copy, Clone)]
315pub enum ProcMacro {
316 CustomDerive {
317 trait_name: &'static str,
318 attributes: &'static [&'static str],
319 client: Client<crate::TokenStream, crate::TokenStream>,
320 },
321
322 Attr {
323 name: &'static str,
324 client: Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream>,
325 },
326
327 Bang {
328 name: &'static str,
329 client: Client<crate::TokenStream, crate::TokenStream>,
330 },
331}
332
333impl ProcMacro {
334 pub fn name(&self) -> &'static str {
335 match self {
336 ProcMacro::CustomDerive { trait_name, .. } => trait_name,
337 ProcMacro::Attr { name, .. } => name,
338 ProcMacro::Bang { name, .. } => name,
339 }
340 }
341
342 pub const fn custom_derive(
343 trait_name: &'static str,
344 attributes: &'static [&'static str],
345 expand: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy,
346 ) -> Self {
347 ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
348 }
349
350 pub const fn attr(
351 name: &'static str,
352 expand: impl Fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream + Copy,
353 ) -> Self {
354 ProcMacro::Attr { name, client: Client::expand2(expand) }
355 }
356
357 pub const fn bang(
358 name: &'static str,
359 expand: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy,
360 ) -> Self {
361 ProcMacro::Bang { name, client: Client::expand1(expand) }
362 }
363}