1 | //! Server-side traits. |
2 | |
3 | use super::*; |
4 | |
5 | use std::cell::Cell; |
6 | use std::marker::PhantomData; |
7 | |
8 | // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. |
9 | use super::client::HandleStore; |
10 | |
11 | pub trait Types { |
12 | type FreeFunctions: 'static; |
13 | type TokenStream: 'static + Clone; |
14 | type SourceFile: 'static + Clone; |
15 | type Span: 'static + Copy + Eq + Hash; |
16 | type Symbol: 'static; |
17 | } |
18 | |
19 | /// Declare an associated fn of one of the traits below, adding necessary |
20 | /// default bodies. |
21 | macro_rules! associated_fn { |
22 | (fn drop(&mut self, $arg:ident: $arg_ty:ty)) => |
23 | (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) }); |
24 | |
25 | (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) => |
26 | (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() }); |
27 | |
28 | ($($item:tt)*) => ($($item)*;) |
29 | } |
30 | |
31 | macro_rules! declare_server_traits { |
32 | ($($name:ident { |
33 | $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* |
34 | }),* $(,)?) => { |
35 | $(pub trait $name: Types { |
36 | $(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* |
37 | })* |
38 | |
39 | pub trait Server: Types $(+ $name)* { |
40 | fn globals(&mut self) -> ExpnGlobals<Self::Span>; |
41 | |
42 | /// Intern a symbol received from RPC |
43 | fn intern_symbol(ident: &str) -> Self::Symbol; |
44 | |
45 | /// Recover the string value of a symbol, and invoke a callback with it. |
46 | fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)); |
47 | } |
48 | } |
49 | } |
50 | with_api!(Self, self_, declare_server_traits); |
51 | |
52 | pub(super) struct MarkedTypes<S: Types>(S); |
53 | |
54 | impl<S: Server> Server for MarkedTypes<S> { |
55 | fn globals(&mut self) -> ExpnGlobals<Self::Span> { |
56 | <_>::mark(unmarked:Server::globals(&mut self.0)) |
57 | } |
58 | fn intern_symbol(ident: &str) -> Self::Symbol { |
59 | <_>::mark(S::intern_symbol(ident)) |
60 | } |
61 | fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { |
62 | S::with_symbol_string(symbol:symbol.unmark(), f) |
63 | } |
64 | } |
65 | |
66 | macro_rules! define_mark_types_impls { |
67 | ($($name:ident { |
68 | $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* |
69 | }),* $(,)?) => { |
70 | impl<S: Types> Types for MarkedTypes<S> { |
71 | $(type $name = Marked<S::$name, client::$name>;)* |
72 | } |
73 | |
74 | $(impl<S: $name> $name for MarkedTypes<S> { |
75 | $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? { |
76 | <_>::mark($name::$method(&mut self.0, $($arg.unmark()),*)) |
77 | })* |
78 | })* |
79 | } |
80 | } |
81 | with_api!(Self, self_, define_mark_types_impls); |
82 | |
83 | struct Dispatcher<S: Types> { |
84 | handle_store: HandleStore<S>, |
85 | server: S, |
86 | } |
87 | |
88 | macro_rules! define_dispatcher_impl { |
89 | ($($name:ident { |
90 | $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* |
91 | }),* $(,)?) => { |
92 | // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. |
93 | pub trait DispatcherTrait { |
94 | // HACK(eddyb) these are here to allow `Self::$name` to work below. |
95 | $(type $name;)* |
96 | |
97 | fn dispatch(&mut self, buf: Buffer) -> Buffer; |
98 | } |
99 | |
100 | impl<S: Server> DispatcherTrait for Dispatcher<MarkedTypes<S>> { |
101 | $(type $name = <MarkedTypes<S> as Types>::$name;)* |
102 | |
103 | fn dispatch(&mut self, mut buf: Buffer) -> Buffer { |
104 | let Dispatcher { handle_store, server } = self; |
105 | |
106 | let mut reader = &buf[..]; |
107 | match api_tags::Method::decode(&mut reader, &mut ()) { |
108 | $(api_tags::Method::$name(m) => match m { |
109 | $(api_tags::$name::$method => { |
110 | let mut call_method = || { |
111 | reverse_decode!(reader, handle_store; $($arg: $arg_ty),*); |
112 | $name::$method(server, $($arg),*) |
113 | }; |
114 | // HACK(eddyb) don't use `panic::catch_unwind` in a panic. |
115 | // If client and server happen to use the same `std`, |
116 | // `catch_unwind` asserts that the panic counter was 0, |
117 | // even when the closure passed to it didn't panic. |
118 | let r = if thread::panicking() { |
119 | Ok(call_method()) |
120 | } else { |
121 | panic::catch_unwind(panic::AssertUnwindSafe(call_method)) |
122 | .map_err(PanicMessage::from) |
123 | }; |
124 | |
125 | buf.clear(); |
126 | r.encode(&mut buf, handle_store); |
127 | })* |
128 | }),* |
129 | } |
130 | buf |
131 | } |
132 | } |
133 | } |
134 | } |
135 | with_api!(Self, self_, define_dispatcher_impl); |
136 | |
137 | pub trait ExecutionStrategy { |
138 | fn run_bridge_and_client( |
139 | &self, |
140 | dispatcher: &mut impl DispatcherTrait, |
141 | input: Buffer, |
142 | run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, |
143 | force_show_panics: bool, |
144 | ) -> Buffer; |
145 | } |
146 | |
147 | thread_local! { |
148 | /// While running a proc-macro with the same-thread executor, this flag will |
149 | /// be set, forcing nested proc-macro invocations (e.g. due to |
150 | /// `TokenStream::expand_expr`) to be run using a cross-thread executor. |
151 | /// |
152 | /// This is required as the thread-local state in the proc_macro client does |
153 | /// not handle being re-entered, and will invalidate all `Symbol`s when |
154 | /// entering a nested macro. |
155 | static ALREADY_RUNNING_SAME_THREAD: Cell<bool> = Cell::new(false); |
156 | } |
157 | |
158 | /// Keep `ALREADY_RUNNING_SAME_THREAD` (see also its documentation) |
159 | /// set to `true`, preventing same-thread reentrance. |
160 | struct RunningSameThreadGuard(()); |
161 | |
162 | impl RunningSameThreadGuard { |
163 | fn new() -> Self { |
164 | let already_running: bool = ALREADY_RUNNING_SAME_THREAD.replace(true); |
165 | assert!( |
166 | !already_running, |
167 | "same-thread nesting ( \"reentrance \") of proc macro executions is not supported" |
168 | ); |
169 | RunningSameThreadGuard(()) |
170 | } |
171 | } |
172 | |
173 | impl Drop for RunningSameThreadGuard { |
174 | fn drop(&mut self) { |
175 | ALREADY_RUNNING_SAME_THREAD.set(false); |
176 | } |
177 | } |
178 | |
179 | pub struct MaybeCrossThread<P> { |
180 | cross_thread: bool, |
181 | marker: PhantomData<P>, |
182 | } |
183 | |
184 | impl<P> MaybeCrossThread<P> { |
185 | pub const fn new(cross_thread: bool) -> Self { |
186 | MaybeCrossThread { cross_thread, marker: PhantomData } |
187 | } |
188 | } |
189 | |
190 | impl<P> ExecutionStrategy for MaybeCrossThread<P> |
191 | where |
192 | P: MessagePipe<Buffer> + Send + 'static, |
193 | { |
194 | fn run_bridge_and_client( |
195 | &self, |
196 | dispatcher: &mut impl DispatcherTrait, |
197 | input: Buffer, |
198 | run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, |
199 | force_show_panics: bool, |
200 | ) -> Buffer { |
201 | if self.cross_thread || ALREADY_RUNNING_SAME_THREAD.get() { |
202 | <CrossThread<P>>::new().run_bridge_and_client( |
203 | dispatcher, |
204 | input, |
205 | run_client, |
206 | force_show_panics, |
207 | ) |
208 | } else { |
209 | SameThread.run_bridge_and_client(dispatcher, input, run_client, force_show_panics) |
210 | } |
211 | } |
212 | } |
213 | |
214 | pub struct SameThread; |
215 | |
216 | impl ExecutionStrategy for SameThread { |
217 | fn run_bridge_and_client( |
218 | &self, |
219 | dispatcher: &mut impl DispatcherTrait, |
220 | input: Buffer, |
221 | run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, |
222 | force_show_panics: bool, |
223 | ) -> Buffer { |
224 | let _guard: RunningSameThreadGuard = RunningSameThreadGuard::new(); |
225 | |
226 | let mut dispatch: impl FnMut(Buffer) -> Buffer = |buf: Buffer| dispatcher.dispatch(buf); |
227 | |
228 | run_client(BridgeConfig { |
229 | input, |
230 | dispatch: (&mut dispatch).into(), |
231 | force_show_panics, |
232 | _marker: marker::PhantomData, |
233 | }) |
234 | } |
235 | } |
236 | |
237 | pub struct CrossThread<P>(PhantomData<P>); |
238 | |
239 | impl<P> CrossThread<P> { |
240 | pub const fn new() -> Self { |
241 | CrossThread(PhantomData) |
242 | } |
243 | } |
244 | |
245 | impl<P> ExecutionStrategy for CrossThread<P> |
246 | where |
247 | P: MessagePipe<Buffer> + Send + 'static, |
248 | { |
249 | fn run_bridge_and_client( |
250 | &self, |
251 | dispatcher: &mut impl DispatcherTrait, |
252 | input: Buffer, |
253 | run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, |
254 | force_show_panics: bool, |
255 | ) -> Buffer { |
256 | let (mut server, mut client) = P::new(); |
257 | |
258 | let join_handle = thread::spawn(move || { |
259 | let mut dispatch = |b: Buffer| -> Buffer { |
260 | client.send(b); |
261 | client.recv().expect("server died while client waiting for reply" ) |
262 | }; |
263 | |
264 | run_client(BridgeConfig { |
265 | input, |
266 | dispatch: (&mut dispatch).into(), |
267 | force_show_panics, |
268 | _marker: marker::PhantomData, |
269 | }) |
270 | }); |
271 | |
272 | while let Some(b) = server.recv() { |
273 | server.send(dispatcher.dispatch(b)); |
274 | } |
275 | |
276 | join_handle.join().unwrap() |
277 | } |
278 | } |
279 | |
280 | /// A message pipe used for communicating between server and client threads. |
281 | pub trait MessagePipe<T>: Sized { |
282 | /// Create a new pair of endpoints for the message pipe. |
283 | fn new() -> (Self, Self); |
284 | |
285 | /// Send a message to the other endpoint of this pipe. |
286 | fn send(&mut self, value: T); |
287 | |
288 | /// Receive a message from the other endpoint of this pipe. |
289 | /// |
290 | /// Returns `None` if the other end of the pipe has been destroyed, and no |
291 | /// message was received. |
292 | fn recv(&mut self) -> Option<T>; |
293 | } |
294 | |
295 | fn run_server< |
296 | S: Server, |
297 | I: Encode<HandleStore<MarkedTypes<S>>>, |
298 | O: for<'a, 's> DecodeMut<'a, 's, HandleStore<MarkedTypes<S>>>, |
299 | >( |
300 | strategy: &impl ExecutionStrategy, |
301 | handle_counters: &'static client::HandleCounters, |
302 | server: S, |
303 | input: I, |
304 | run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, |
305 | force_show_panics: bool, |
306 | ) -> Result<O, PanicMessage> { |
307 | let mut dispatcher: Dispatcher> = |
308 | Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; |
309 | |
310 | let globals: ExpnGlobals::Span, …>> = dispatcher.server.globals(); |
311 | |
312 | let mut buf: Buffer = Buffer::new(); |
313 | (globals, input).encode(&mut buf, &mut dispatcher.handle_store); |
314 | |
315 | buf = strategy.run_bridge_and_client(&mut dispatcher, input:buf, run_client, force_show_panics); |
316 | |
317 | Result::decode(&mut &buf[..], &mut dispatcher.handle_store) |
318 | } |
319 | |
320 | impl client::Client<crate::TokenStream, crate::TokenStream> { |
321 | pub fn run<S>( |
322 | &self, |
323 | strategy: &impl ExecutionStrategy, |
324 | server: S, |
325 | input: S::TokenStream, |
326 | force_show_panics: bool, |
327 | ) -> Result<S::TokenStream, PanicMessage> |
328 | where |
329 | S: Server, |
330 | S::TokenStream: Default, |
331 | { |
332 | let client::Client { get_handle_counters: fn() -> &HandleCounters, run: fn(BridgeConfig<'_>) -> Buffer, _marker: PhantomData …> } = *self; |
333 | run_server( |
334 | strategy, |
335 | get_handle_counters(), |
336 | server, |
337 | <MarkedTypes<S> as Types>::TokenStream::mark(input), |
338 | run, |
339 | force_show_panics, |
340 | ) |
341 | .map(|s: Option::TokenStream, …>>| <Option<<MarkedTypes<S> as Types>::TokenStream>>::unmark(self:s).unwrap_or_default()) |
342 | } |
343 | } |
344 | |
345 | impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream> { |
346 | pub fn run<S>( |
347 | &self, |
348 | strategy: &impl ExecutionStrategy, |
349 | server: S, |
350 | input: S::TokenStream, |
351 | input2: S::TokenStream, |
352 | force_show_panics: bool, |
353 | ) -> Result<S::TokenStream, PanicMessage> |
354 | where |
355 | S: Server, |
356 | S::TokenStream: Default, |
357 | { |
358 | let client::Client { get_handle_counters, run, _marker } = *self; |
359 | run_server( |
360 | strategy, |
361 | get_handle_counters(), |
362 | server, |
363 | ( |
364 | <MarkedTypes<S> as Types>::TokenStream::mark(input), |
365 | <MarkedTypes<S> as Types>::TokenStream::mark(input2), |
366 | ), |
367 | run, |
368 | force_show_panics, |
369 | ) |
370 | .map(|s| <Option<<MarkedTypes<S> as Types>::TokenStream>>::unmark(s).unwrap_or_default()) |
371 | } |
372 | } |
373 | |