@@ -230,6 +230,20 @@ impl Clone for SourceFile {
230
230
}
231
231
}
232
232
233
+ impl Span {
234
+ pub ( crate ) fn def_site ( ) -> Span {
235
+ Bridge :: with ( |bridge| bridge. context . def_site )
236
+ }
237
+
238
+ pub ( crate ) fn call_site ( ) -> Span {
239
+ Bridge :: with ( |bridge| bridge. context . call_site )
240
+ }
241
+
242
+ pub ( crate ) fn mixed_site ( ) -> Span {
243
+ Bridge :: with ( |bridge| bridge. context . mixed_site )
244
+ }
245
+ }
246
+
233
247
impl fmt:: Debug for Span {
234
248
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
235
249
f. write_str ( & self . debug ( ) )
@@ -263,6 +277,21 @@ macro_rules! define_client_side {
263
277
}
264
278
with_api ! ( self , self , define_client_side) ;
265
279
280
+ struct Bridge < ' a > {
281
+ /// Reusable buffer (only `clear`-ed, never shrunk), primarily
282
+ /// used for making requests.
283
+ cached_buffer : Buffer ,
284
+
285
+ /// Server-side function that the client uses to make requests.
286
+ dispatch : closure:: Closure < ' a , Buffer , Buffer > ,
287
+
288
+ /// Provided context for this macro expansion.
289
+ context : ExpnContext < Span > ,
290
+ }
291
+
292
+ impl < ' a > !Send for Bridge < ' a > { }
293
+ impl < ' a > !Sync for Bridge < ' a > { }
294
+
266
295
enum BridgeState < ' a > {
267
296
/// No server is currently connected to this client.
268
297
NotConnected ,
@@ -305,34 +334,6 @@ impl BridgeState<'_> {
305
334
}
306
335
307
336
impl Bridge < ' _ > {
308
- pub ( crate ) fn is_available ( ) -> bool {
309
- BridgeState :: with ( |state| match state {
310
- BridgeState :: Connected ( _) | BridgeState :: InUse => true ,
311
- BridgeState :: NotConnected => false ,
312
- } )
313
- }
314
-
315
- fn enter < R > ( self , f : impl FnOnce ( ) -> R ) -> R {
316
- let force_show_panics = self . force_show_panics ;
317
- // Hide the default panic output within `proc_macro` expansions.
318
- // NB. the server can't do this because it may use a different libstd.
319
- static HIDE_PANICS_DURING_EXPANSION : Once = Once :: new ( ) ;
320
- HIDE_PANICS_DURING_EXPANSION . call_once ( || {
321
- let prev = panic:: take_hook ( ) ;
322
- panic:: set_hook ( Box :: new ( move |info| {
323
- let show = BridgeState :: with ( |state| match state {
324
- BridgeState :: NotConnected => true ,
325
- BridgeState :: Connected ( _) | BridgeState :: InUse => force_show_panics,
326
- } ) ;
327
- if show {
328
- prev ( info)
329
- }
330
- } ) ) ;
331
- } ) ;
332
-
333
- BRIDGE_STATE . with ( |state| state. set ( BridgeState :: Connected ( self ) , f) )
334
- }
335
-
336
337
fn with < R > ( f : impl FnOnce ( & mut Bridge < ' _ > ) -> R ) -> R {
337
338
BridgeState :: with ( |state| match state {
338
339
BridgeState :: NotConnected => {
@@ -346,6 +347,13 @@ impl Bridge<'_> {
346
347
}
347
348
}
348
349
350
+ pub ( crate ) fn is_available ( ) -> bool {
351
+ BridgeState :: with ( |state| match state {
352
+ BridgeState :: Connected ( _) | BridgeState :: InUse => true ,
353
+ BridgeState :: NotConnected => false ,
354
+ } )
355
+ }
356
+
349
357
/// A client-side RPC entry-point, which may be using a different `proc_macro`
350
358
/// from the one used by the server, but can be invoked compatibly.
351
359
///
@@ -363,7 +371,7 @@ pub struct Client<I, O> {
363
371
// a wrapper `fn` pointer, once `const fn` can reference `static`s.
364
372
pub ( super ) get_handle_counters : extern "C" fn ( ) -> & ' static HandleCounters ,
365
373
366
- pub ( super ) run : extern "C" fn ( Bridge < ' _ > ) -> Buffer ,
374
+ pub ( super ) run : extern "C" fn ( BridgeConfig < ' _ > ) -> Buffer ,
367
375
368
376
pub ( super ) _marker : PhantomData < fn ( I ) -> O > ,
369
377
}
@@ -375,40 +383,62 @@ impl<I, O> Clone for Client<I, O> {
375
383
}
376
384
}
377
385
386
+ fn maybe_install_panic_hook ( force_show_panics : bool ) {
387
+ // Hide the default panic output within `proc_macro` expansions.
388
+ // NB. the server can't do this because it may use a different libstd.
389
+ static HIDE_PANICS_DURING_EXPANSION : Once = Once :: new ( ) ;
390
+ HIDE_PANICS_DURING_EXPANSION . call_once ( || {
391
+ let prev = panic:: take_hook ( ) ;
392
+ panic:: set_hook ( Box :: new ( move |info| {
393
+ let show = BridgeState :: with ( |state| match state {
394
+ BridgeState :: NotConnected => true ,
395
+ BridgeState :: Connected ( _) | BridgeState :: InUse => force_show_panics,
396
+ } ) ;
397
+ if show {
398
+ prev ( info)
399
+ }
400
+ } ) ) ;
401
+ } ) ;
402
+ }
403
+
378
404
/// Client-side helper for handling client panics, entering the bridge,
379
405
/// deserializing input and serializing output.
380
406
// FIXME(eddyb) maybe replace `Bridge::enter` with this?
381
407
fn run_client < A : for < ' a , ' s > DecodeMut < ' a , ' s , ( ) > , R : Encode < ( ) > > (
382
- mut bridge : Bridge < ' _ > ,
408
+ config : BridgeConfig < ' _ > ,
383
409
f : impl FnOnce ( A ) -> R ,
384
410
) -> Buffer {
385
- // The initial `cached_buffer` contains the input.
386
- let mut buf = bridge. cached_buffer . take ( ) ;
411
+ let BridgeConfig { input : mut buf, dispatch, force_show_panics, .. } = config;
387
412
388
413
panic:: catch_unwind ( panic:: AssertUnwindSafe ( || {
389
- bridge. enter ( || {
390
- let reader = & mut & buf[ ..] ;
391
- let input = A :: decode ( reader, & mut ( ) ) ;
392
-
393
- // Put the `cached_buffer` back in the `Bridge`, for requests.
394
- Bridge :: with ( |bridge| bridge. cached_buffer = buf. take ( ) ) ;
395
-
396
- let output = f ( input) ;
397
-
398
- // Take the `cached_buffer` back out, for the output value.
399
- buf = Bridge :: with ( |bridge| bridge. cached_buffer . take ( ) ) ;
400
-
401
- // HACK(eddyb) Separate encoding a success value (`Ok(output)`)
402
- // from encoding a panic (`Err(e: PanicMessage)`) to avoid
403
- // having handles outside the `bridge.enter(|| ...)` scope, and
404
- // to catch panics that could happen while encoding the success.
405
- //
406
- // Note that panics should be impossible beyond this point, but
407
- // this is defensively trying to avoid any accidental panicking
408
- // reaching the `extern "C"` (which should `abort` but might not
409
- // at the moment, so this is also potentially preventing UB).
410
- buf. clear ( ) ;
411
- Ok :: < _ , ( ) > ( output) . encode ( & mut buf, & mut ( ) ) ;
414
+ maybe_install_panic_hook ( force_show_panics) ;
415
+
416
+ let reader = & mut & buf[ ..] ;
417
+ let ( input, context) = <( A , ExpnContext < Span > ) >:: decode ( reader, & mut ( ) ) ;
418
+
419
+ // Put the buffer we used for input back in the `Bridge` for requests.
420
+ let new_state =
421
+ BridgeState :: Connected ( Bridge { cached_buffer : buf. take ( ) , dispatch, context } ) ;
422
+
423
+ BRIDGE_STATE . with ( |state| {
424
+ state. set ( new_state, || {
425
+ let output = f ( input) ;
426
+
427
+ // Take the `cached_buffer` back out, for the output value.
428
+ buf = Bridge :: with ( |bridge| bridge. cached_buffer . take ( ) ) ;
429
+
430
+ // HACK(eddyb) Separate encoding a success value (`Ok(output)`)
431
+ // from encoding a panic (`Err(e: PanicMessage)`) to avoid
432
+ // having handles outside the `bridge.enter(|| ...)` scope, and
433
+ // to catch panics that could happen while encoding the success.
434
+ //
435
+ // Note that panics should be impossible beyond this point, but
436
+ // this is defensively trying to avoid any accidental panicking
437
+ // reaching the `extern "C"` (which should `abort` but might not
438
+ // at the moment, so this is also potentially preventing UB).
439
+ buf. clear ( ) ;
440
+ Ok :: < _ , ( ) > ( output) . encode ( & mut buf, & mut ( ) ) ;
441
+ } )
412
442
} )
413
443
} ) )
414
444
. map_err ( PanicMessage :: from)
0 commit comments