@@ -230,6 +230,20 @@ impl Clone for SourceFile {
230230 }
231231}
232232
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+
233247impl fmt:: Debug for Span {
234248 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
235249 f. write_str ( & self . debug ( ) )
@@ -263,6 +277,21 @@ macro_rules! define_client_side {
263277}
264278with_api ! ( self , self , define_client_side) ;
265279
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+
266295enum BridgeState < ' a > {
267296 /// No server is currently connected to this client.
268297 NotConnected ,
@@ -305,34 +334,6 @@ impl BridgeState<'_> {
305334}
306335
307336impl 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-
336337 fn with < R > ( f : impl FnOnce ( & mut Bridge < ' _ > ) -> R ) -> R {
337338 BridgeState :: with ( |state| match state {
338339 BridgeState :: NotConnected => {
@@ -346,6 +347,13 @@ impl Bridge<'_> {
346347 }
347348}
348349
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+
349357/// A client-side RPC entry-point, which may be using a different `proc_macro`
350358/// from the one used by the server, but can be invoked compatibly.
351359///
@@ -363,7 +371,7 @@ pub struct Client<I, O> {
363371 // a wrapper `fn` pointer, once `const fn` can reference `static`s.
364372 pub ( super ) get_handle_counters : extern "C" fn ( ) -> & ' static HandleCounters ,
365373
366- pub ( super ) run : extern "C" fn ( Bridge < ' _ > ) -> Buffer ,
374+ pub ( super ) run : extern "C" fn ( BridgeConfig < ' _ > ) -> Buffer ,
367375
368376 pub ( super ) _marker : PhantomData < fn ( I ) -> O > ,
369377}
@@ -375,40 +383,62 @@ impl<I, O> Clone for Client<I, O> {
375383 }
376384}
377385
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+
378404/// Client-side helper for handling client panics, entering the bridge,
379405/// deserializing input and serializing output.
380406// FIXME(eddyb) maybe replace `Bridge::enter` with this?
381407fn run_client < A : for < ' a , ' s > DecodeMut < ' a , ' s , ( ) > , R : Encode < ( ) > > (
382- mut bridge : Bridge < ' _ > ,
408+ config : BridgeConfig < ' _ > ,
383409 f : impl FnOnce ( A ) -> R ,
384410) -> 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;
387412
388413 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+ } )
412442 } )
413443 } ) )
414444 . map_err ( PanicMessage :: from)
0 commit comments