aboutsummaryrefslogtreecommitdiff
path: root/crates/proc_macro_srv/src/proc_macro/bridge/server.rs
diff options
context:
space:
mode:
authorPavan Kumar Sunkara <[email protected]>2020-08-13 01:57:26 +0100
committerPavan Kumar Sunkara <[email protected]>2020-08-13 02:18:19 +0100
commit349e6c62ada1fa45a8b80edb877b5e7c9d0c306d (patch)
treec08cb7cd48089c1c7316ff2570de02df76e9d9ef /crates/proc_macro_srv/src/proc_macro/bridge/server.rs
parentf277ec27ac024992e8b8834c68e16b31c983be1b (diff)
Rename ra_proc_macro_srv -> proc_macro_srv
Diffstat (limited to 'crates/proc_macro_srv/src/proc_macro/bridge/server.rs')
-rw-r--r--crates/proc_macro_srv/src/proc_macro/bridge/server.rs323
1 files changed, 323 insertions, 0 deletions
diff --git a/crates/proc_macro_srv/src/proc_macro/bridge/server.rs b/crates/proc_macro_srv/src/proc_macro/bridge/server.rs
new file mode 100644
index 000000000..45d41ac02
--- /dev/null
+++ b/crates/proc_macro_srv/src/proc_macro/bridge/server.rs
@@ -0,0 +1,323 @@
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
6use super::*;
7
8// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
9use super::client::HandleStore;
10
11/// Declare an associated item of one of the traits below, optionally
12/// adjusting it (i.e., adding bounds to types and default bodies to methods).
13macro_rules! associated_item {
14 (type TokenStream) =>
15 (type TokenStream: 'static + Clone;);
16 (type TokenStreamBuilder) =>
17 (type TokenStreamBuilder: 'static;);
18 (type TokenStreamIter) =>
19 (type TokenStreamIter: 'static + Clone;);
20 (type Group) =>
21 (type Group: 'static + Clone;);
22 (type Punct) =>
23 (type Punct: 'static + Copy + Eq + Hash;);
24 (type Ident) =>
25 (type Ident: 'static + Copy + Eq + Hash;);
26 (type Literal) =>
27 (type Literal: 'static + Clone;);
28 (type SourceFile) =>
29 (type SourceFile: 'static + Clone;);
30 (type MultiSpan) =>
31 (type MultiSpan: 'static;);
32 (type Diagnostic) =>
33 (type Diagnostic: 'static;);
34 (type Span) =>
35 (type Span: 'static + Copy + Eq + Hash;);
36 (fn drop(&mut self, $arg:ident: $arg_ty:ty)) =>
37 (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) });
38 (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) =>
39 (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() });
40 ($($item:tt)*) => ($($item)*;)
41}
42
43macro_rules! declare_server_traits {
44 ($($name:ident {
45 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
46 }),* $(,)?) => {
47 pub trait Types {
48 $(associated_item!(type $name);)*
49 }
50
51 $(pub trait $name: Types {
52 $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)*
53 })*
54
55 pub trait Server: Types $(+ $name)* {}
56 impl<S: Types $(+ $name)*> Server for S {}
57 }
58}
59with_api!(Self, self_, declare_server_traits);
60
61pub(super) struct MarkedTypes<S: Types>(S);
62
63macro_rules! define_mark_types_impls {
64 ($($name:ident {
65 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
66 }),* $(,)?) => {
67 impl<S: Types> Types for MarkedTypes<S> {
68 $(type $name = Marked<S::$name, client::$name>;)*
69 }
70
71 $(impl<S: $name> $name for MarkedTypes<S> {
72 $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)? {
73 <_>::mark($name::$method(&mut self.0, $($arg.unmark()),*))
74 })*
75 })*
76 }
77}
78with_api!(Self, self_, define_mark_types_impls);
79
80struct Dispatcher<S: Types> {
81 handle_store: HandleStore<S>,
82 server: S,
83}
84
85macro_rules! define_dispatcher_impl {
86 ($($name:ident {
87 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
88 }),* $(,)?) => {
89 // FIXME(eddyb) `pub` only for `ExecutionStrategy` below.
90 pub trait DispatcherTrait {
91 // HACK(eddyb) these are here to allow `Self::$name` to work below.
92 $(type $name;)*
93 fn dispatch(&mut self, b: Buffer<u8>) -> Buffer<u8>;
94 }
95
96 impl<S: Server> DispatcherTrait for Dispatcher<MarkedTypes<S>> {
97 $(type $name = <MarkedTypes<S> as Types>::$name;)*
98 fn dispatch(&mut self, mut b: Buffer<u8>) -> Buffer<u8> {
99 let Dispatcher { handle_store, server } = self;
100
101 let mut reader = &b[..];
102 match api_tags::Method::decode(&mut reader, &mut ()) {
103 $(api_tags::Method::$name(m) => match m {
104 $(api_tags::$name::$method => {
105 let mut call_method = || {
106 reverse_decode!(reader, handle_store; $($arg: $arg_ty),*);
107 $name::$method(server, $($arg),*)
108 };
109 // HACK(eddyb) don't use `panic::catch_unwind` in a panic.
110 // If client and server happen to use the same `libstd`,
111 // `catch_unwind` asserts that the panic counter was 0,
112 // even when the closure passed to it didn't panic.
113 let r = if thread::panicking() {
114 Ok(call_method())
115 } else {
116 panic::catch_unwind(panic::AssertUnwindSafe(call_method))
117 .map_err(PanicMessage::from)
118 };
119
120 b.clear();
121 r.encode(&mut b, handle_store);
122 })*
123 }),*
124 }
125 b
126 }
127 }
128 }
129}
130with_api!(Self, self_, define_dispatcher_impl);
131
132pub trait ExecutionStrategy {
133 fn run_bridge_and_client<D: Copy + Send + 'static>(
134 &self,
135 dispatcher: &mut impl DispatcherTrait,
136 input: Buffer<u8>,
137 run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
138 client_data: D,
139 ) -> Buffer<u8>;
140}
141
142pub struct SameThread;
143
144impl ExecutionStrategy for SameThread {
145 fn run_bridge_and_client<D: Copy + Send + 'static>(
146 &self,
147 dispatcher: &mut impl DispatcherTrait,
148 input: Buffer<u8>,
149 run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
150 client_data: D,
151 ) -> Buffer<u8> {
152 let mut dispatch = |b| dispatcher.dispatch(b);
153
154 run_client(Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, client_data)
155 }
156}
157
158// NOTE(eddyb) Two implementations are provided, the second one is a bit
159// faster but neither is anywhere near as fast as same-thread execution.
160
161pub struct CrossThread1;
162
163impl ExecutionStrategy for CrossThread1 {
164 fn run_bridge_and_client<D: Copy + Send + 'static>(
165 &self,
166 dispatcher: &mut impl DispatcherTrait,
167 input: Buffer<u8>,
168 run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
169 client_data: D,
170 ) -> Buffer<u8> {
171 use std::sync::mpsc::channel;
172
173 let (req_tx, req_rx) = channel();
174 let (res_tx, res_rx) = channel();
175
176 let join_handle = thread::spawn(move || {
177 let mut dispatch = |b| {
178 req_tx.send(b).unwrap();
179 res_rx.recv().unwrap()
180 };
181
182 run_client(
183 Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() },
184 client_data,
185 )
186 });
187
188 for b in req_rx {
189 res_tx.send(dispatcher.dispatch(b)).unwrap();
190 }
191
192 join_handle.join().unwrap()
193 }
194}
195
196pub struct CrossThread2;
197
198impl ExecutionStrategy for CrossThread2 {
199 fn run_bridge_and_client<D: Copy + Send + 'static>(
200 &self,
201 dispatcher: &mut impl DispatcherTrait,
202 input: Buffer<u8>,
203 run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
204 client_data: D,
205 ) -> Buffer<u8> {
206 use std::sync::{Arc, Mutex};
207
208 enum State<T> {
209 Req(T),
210 Res(T),
211 }
212
213 let mut state = Arc::new(Mutex::new(State::Res(Buffer::new())));
214
215 let server_thread = thread::current();
216 let state2 = state.clone();
217 let join_handle = thread::spawn(move || {
218 let mut dispatch = |b| {
219 *state2.lock().unwrap() = State::Req(b);
220 server_thread.unpark();
221 loop {
222 thread::park();
223 if let State::Res(b) = &mut *state2.lock().unwrap() {
224 break b.take();
225 }
226 }
227 };
228
229 let r = run_client(
230 Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() },
231 client_data,
232 );
233
234 // Wake up the server so it can exit the dispatch loop.
235 drop(state2);
236 server_thread.unpark();
237
238 r
239 });
240
241 // Check whether `state2` was dropped, to know when to stop.
242 while Arc::get_mut(&mut state).is_none() {
243 thread::park();
244 let mut b = match &mut *state.lock().unwrap() {
245 State::Req(b) => b.take(),
246 _ => continue,
247 };
248 b = dispatcher.dispatch(b.take());
249 *state.lock().unwrap() = State::Res(b);
250 join_handle.thread().unpark();
251 }
252
253 join_handle.join().unwrap()
254 }
255}
256
257fn run_server<
258 S: Server,
259 I: Encode<HandleStore<MarkedTypes<S>>>,
260 O: for<'a, 's> DecodeMut<'a, 's, HandleStore<MarkedTypes<S>>>,
261 D: Copy + Send + 'static,
262>(
263 strategy: &impl ExecutionStrategy,
264 handle_counters: &'static client::HandleCounters,
265 server: S,
266 input: I,
267 run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
268 client_data: D,
269) -> Result<O, PanicMessage> {
270 let mut dispatcher =
271 Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) };
272
273 let mut b = Buffer::new();
274 input.encode(&mut b, &mut dispatcher.handle_store);
275
276 b = strategy.run_bridge_and_client(&mut dispatcher, b, run_client, client_data);
277
278 Result::decode(&mut &b[..], &mut dispatcher.handle_store)
279}
280
281impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> {
282 pub fn run<S: Server>(
283 &self,
284 strategy: &impl ExecutionStrategy,
285 server: S,
286 input: S::TokenStream,
287 ) -> Result<S::TokenStream, PanicMessage> {
288 let client::Client { get_handle_counters, run, f } = *self;
289 run_server(
290 strategy,
291 get_handle_counters(),
292 server,
293 <MarkedTypes<S> as Types>::TokenStream::mark(input),
294 run,
295 f,
296 )
297 .map(<MarkedTypes<S> as Types>::TokenStream::unmark)
298 }
299}
300
301impl client::Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
302 pub fn run<S: Server>(
303 &self,
304 strategy: &impl ExecutionStrategy,
305 server: S,
306 input: S::TokenStream,
307 input2: S::TokenStream,
308 ) -> Result<S::TokenStream, PanicMessage> {
309 let client::Client { get_handle_counters, run, f } = *self;
310 run_server(
311 strategy,
312 get_handle_counters(),
313 server,
314 (
315 <MarkedTypes<S> as Types>::TokenStream::mark(input),
316 <MarkedTypes<S> as Types>::TokenStream::mark(input2),
317 ),
318 run,
319 f,
320 )
321 .map(<MarkedTypes<S> as Types>::TokenStream::unmark)
322 }
323}