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