1 //! lib-proc-macro server-side traits
2 //!
3 //! Copy from <https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/server.rs>
4 //! augmented with removing unstable features
5 
6 use super::super::TokenStream as CrateTokenStream;
7 use super::*;
8 
9 // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
10 use super::client::HandleStore;
11 
12 /// Declare an associated item of one of the traits below, optionally
13 /// adjusting it (i.e., adding bounds to types and default bodies to methods).
14 macro_rules! associated_item {
15     (type FreeFunctions) =>
16         (type FreeFunctions: 'static;);
17     (type TokenStream) =>
18         (type TokenStream: 'static + Clone;);
19     (type TokenStreamBuilder) =>
20         (type TokenStreamBuilder: 'static;);
21     (type TokenStreamIter) =>
22         (type TokenStreamIter: 'static + Clone;);
23     (type Group) =>
24         (type Group: 'static + Clone;);
25     (type Punct) =>
26         (type Punct: 'static + Copy + Eq + Hash;);
27     (type Ident) =>
28         (type Ident: 'static + Copy + Eq + Hash;);
29     (type Literal) =>
30         (type Literal: 'static + Clone;);
31     (type SourceFile) =>
32         (type SourceFile: 'static + Clone;);
33     (type MultiSpan) =>
34         (type MultiSpan: 'static;);
35     (type Diagnostic) =>
36         (type Diagnostic: 'static;);
37     (type Span) =>
38         (type Span: 'static + Copy + Eq + Hash;);
39     (fn drop(&mut self, $arg:ident: $arg_ty:ty)) =>
40         (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) });
41     (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) =>
42         (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() });
43     ($($item:tt)*) => ($($item)*;)
44 }
45 
46 macro_rules! declare_server_traits {
47     ($($name:ident {
48         $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
49     }),* $(,)?) => {
50         pub trait Types {
51             $(associated_item!(type $name);)*
52         }
53 
54         $(pub trait $name: Types {
55             $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)*
56         })*
57 
58         pub trait Server: Types $(+ $name)* {}
59         impl<S: Types $(+ $name)*> Server for S {}
60     }
61 }
62 with_api!(Self, self_, declare_server_traits);
63 
64 pub(super) struct MarkedTypes<S: Types>(S);
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             fn dispatch(&mut self, b: Buffer<u8>) -> Buffer<u8>;
97         }
98 
99         impl<S: Server> DispatcherTrait for Dispatcher<MarkedTypes<S>> {
100             $(type $name = <MarkedTypes<S> as Types>::$name;)*
101             fn dispatch(&mut self, mut b: Buffer<u8>) -> Buffer<u8> {
102                 let Dispatcher { handle_store, server } = self;
103 
104                 let mut reader = &b[..];
105                 match api_tags::Method::decode(&mut reader, &mut ()) {
106                     $(api_tags::Method::$name(m) => match m {
107                         $(api_tags::$name::$method => {
108                             let mut call_method = || {
109                                 reverse_decode!(reader, handle_store; $($arg: $arg_ty),*);
110                                 $name::$method(server, $($arg),*)
111                             };
112                             // HACK(eddyb) don't use `panic::catch_unwind` in a panic.
113                             // If client and server happen to use the same `libstd`,
114                             // `catch_unwind` asserts that the panic counter was 0,
115                             // even when the closure passed to it didn't panic.
116                             let r = if thread::panicking() {
117                                 Ok(call_method())
118                             } else {
119                                 panic::catch_unwind(panic::AssertUnwindSafe(call_method))
120                                     .map_err(PanicMessage::from)
121                             };
122 
123                             b.clear();
124                             r.encode(&mut b, handle_store);
125                         })*
126                     }),*
127                 }
128                 b
129             }
130         }
131     }
132 }
133 with_api!(Self, self_, define_dispatcher_impl);
134 
135 pub trait ExecutionStrategy {
run_bridge_and_client<D: Copy + Send + 'static>( &self, dispatcher: &mut impl DispatcherTrait, input: Buffer<u8>, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, client_data: D, force_show_panics: bool, ) -> Buffer<u8>136     fn run_bridge_and_client<D: Copy + Send + 'static>(
137         &self,
138         dispatcher: &mut impl DispatcherTrait,
139         input: Buffer<u8>,
140         run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
141         client_data: D,
142         force_show_panics: bool,
143     ) -> Buffer<u8>;
144 }
145 
146 pub struct SameThread;
147 
148 impl ExecutionStrategy for SameThread {
run_bridge_and_client<D: Copy + Send + 'static>( &self, dispatcher: &mut impl DispatcherTrait, input: Buffer<u8>, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, client_data: D, force_show_panics: bool, ) -> Buffer<u8>149     fn run_bridge_and_client<D: Copy + Send + 'static>(
150         &self,
151         dispatcher: &mut impl DispatcherTrait,
152         input: Buffer<u8>,
153         run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
154         client_data: D,
155         force_show_panics: bool,
156     ) -> Buffer<u8> {
157         let mut dispatch = |b| dispatcher.dispatch(b);
158 
159         run_client(
160             Bridge { cached_buffer: input, dispatch: (&mut dispatch).into(), force_show_panics },
161             client_data,
162         )
163     }
164 }
165 
166 // NOTE(eddyb) Two implementations are provided, the second one is a bit
167 // faster but neither is anywhere near as fast as same-thread execution.
168 
169 pub struct CrossThread1;
170 
171 impl ExecutionStrategy for CrossThread1 {
run_bridge_and_client<D: Copy + Send + 'static>( &self, dispatcher: &mut impl DispatcherTrait, input: Buffer<u8>, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, client_data: D, force_show_panics: bool, ) -> Buffer<u8>172     fn run_bridge_and_client<D: Copy + Send + 'static>(
173         &self,
174         dispatcher: &mut impl DispatcherTrait,
175         input: Buffer<u8>,
176         run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
177         client_data: D,
178         force_show_panics: bool,
179     ) -> Buffer<u8> {
180         use std::sync::mpsc::channel;
181 
182         let (req_tx, req_rx) = channel();
183         let (res_tx, res_rx) = channel();
184 
185         let join_handle = thread::spawn(move || {
186             let mut dispatch = |b| {
187                 req_tx.send(b).unwrap();
188                 res_rx.recv().unwrap()
189             };
190 
191             run_client(
192                 Bridge {
193                     cached_buffer: input,
194                     dispatch: (&mut dispatch).into(),
195                     force_show_panics,
196                 },
197                 client_data,
198             )
199         });
200 
201         for b in req_rx {
202             res_tx.send(dispatcher.dispatch(b)).unwrap();
203         }
204 
205         join_handle.join().unwrap()
206     }
207 }
208 
209 pub struct CrossThread2;
210 
211 impl ExecutionStrategy for CrossThread2 {
run_bridge_and_client<D: Copy + Send + 'static>( &self, dispatcher: &mut impl DispatcherTrait, input: Buffer<u8>, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, client_data: D, force_show_panics: bool, ) -> Buffer<u8>212     fn run_bridge_and_client<D: Copy + Send + 'static>(
213         &self,
214         dispatcher: &mut impl DispatcherTrait,
215         input: Buffer<u8>,
216         run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
217         client_data: D,
218         force_show_panics: bool,
219     ) -> Buffer<u8> {
220         use std::sync::{Arc, Mutex};
221 
222         enum State<T> {
223             Req(T),
224             Res(T),
225         }
226 
227         let mut state = Arc::new(Mutex::new(State::Res(Buffer::new())));
228 
229         let server_thread = thread::current();
230         let state2 = state.clone();
231         let join_handle = thread::spawn(move || {
232             let mut dispatch = |b| {
233                 *state2.lock().unwrap() = State::Req(b);
234                 server_thread.unpark();
235                 loop {
236                     thread::park();
237                     if let State::Res(b) = &mut *state2.lock().unwrap() {
238                         break b.take();
239                     }
240                 }
241             };
242 
243             let r = run_client(
244                 Bridge {
245                     cached_buffer: input,
246                     dispatch: (&mut dispatch).into(),
247                     force_show_panics,
248                 },
249                 client_data,
250             );
251 
252             // Wake up the server so it can exit the dispatch loop.
253             drop(state2);
254             server_thread.unpark();
255 
256             r
257         });
258 
259         // Check whether `state2` was dropped, to know when to stop.
260         while Arc::get_mut(&mut state).is_none() {
261             thread::park();
262             let mut b = match &mut *state.lock().unwrap() {
263                 State::Req(b) => b.take(),
264                 _ => continue,
265             };
266             b = dispatcher.dispatch(b.take());
267             *state.lock().unwrap() = State::Res(b);
268             join_handle.thread().unpark();
269         }
270 
271         join_handle.join().unwrap()
272     }
273 }
274 
run_server< S: Server, I: Encode<HandleStore<MarkedTypes<S>>>, O: for<'a, 's> DecodeMut<'a, 's, HandleStore<MarkedTypes<S>>>, D: Copy + Send + 'static, >( strategy: &impl ExecutionStrategy, handle_counters: &'static client::HandleCounters, server: S, input: I, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, client_data: D, force_show_panics: bool, ) -> Result<O, PanicMessage>275 fn run_server<
276     S: Server,
277     I: Encode<HandleStore<MarkedTypes<S>>>,
278     O: for<'a, 's> DecodeMut<'a, 's, HandleStore<MarkedTypes<S>>>,
279     D: Copy + Send + 'static,
280 >(
281     strategy: &impl ExecutionStrategy,
282     handle_counters: &'static client::HandleCounters,
283     server: S,
284     input: I,
285     run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
286     client_data: D,
287     force_show_panics: bool,
288 ) -> Result<O, PanicMessage> {
289     let mut dispatcher =
290         Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) };
291 
292     let mut b = Buffer::new();
293     input.encode(&mut b, &mut dispatcher.handle_store);
294 
295     b = strategy.run_bridge_and_client(
296         &mut dispatcher,
297         b,
298         run_client,
299         client_data,
300         force_show_panics,
301     );
302 
303     Result::decode(&mut &b[..], &mut dispatcher.handle_store)
304 }
305 
306 impl client::Client<fn(CrateTokenStream) -> CrateTokenStream> {
run<S: Server>( &self, strategy: &impl ExecutionStrategy, server: S, input: S::TokenStream, force_show_panics: bool, ) -> Result<S::TokenStream, PanicMessage>307     pub fn run<S: Server>(
308         &self,
309         strategy: &impl ExecutionStrategy,
310         server: S,
311         input: S::TokenStream,
312         force_show_panics: bool,
313     ) -> Result<S::TokenStream, PanicMessage> {
314         let client::Client { get_handle_counters, run, f } = *self;
315         run_server(
316             strategy,
317             get_handle_counters(),
318             server,
319             <MarkedTypes<S> as Types>::TokenStream::mark(input),
320             run,
321             f,
322             force_show_panics,
323         )
324         .map(<MarkedTypes<S> as Types>::TokenStream::unmark)
325     }
326 }
327 
328 impl client::Client<fn(CrateTokenStream, CrateTokenStream) -> CrateTokenStream> {
run<S: Server>( &self, strategy: &impl ExecutionStrategy, server: S, input: S::TokenStream, input2: S::TokenStream, force_show_panics: bool, ) -> Result<S::TokenStream, PanicMessage>329     pub fn run<S: Server>(
330         &self,
331         strategy: &impl ExecutionStrategy,
332         server: S,
333         input: S::TokenStream,
334         input2: S::TokenStream,
335         force_show_panics: bool,
336     ) -> Result<S::TokenStream, PanicMessage> {
337         let client::Client { get_handle_counters, run, f } = *self;
338         run_server(
339             strategy,
340             get_handle_counters(),
341             server,
342             (
343                 <MarkedTypes<S> as Types>::TokenStream::mark(input),
344                 <MarkedTypes<S> as Types>::TokenStream::mark(input2),
345             ),
346             run,
347             f,
348             force_show_panics,
349         )
350         .map(<MarkedTypes<S> as Types>::TokenStream::unmark)
351     }
352 }
353