@@ -5,6 +5,9 @@ use std::marker::PhantomData;
55use std:: sync:: atomic:: AtomicU32 ;
66
77use super :: * ;
8+ use crate :: StandaloneLevel ;
9+ use crate :: bridge:: server:: { Dispatcher , DispatcherTrait } ;
10+ use crate :: bridge:: standalone:: NoRustc ;
811
912macro_rules! define_client_handles {
1013 (
@@ -141,7 +144,10 @@ macro_rules! define_client_side {
141144 api_tags:: Method :: $name( api_tags:: $name:: $method) . encode( & mut buf, & mut ( ) ) ;
142145 $( $arg. encode( & mut buf, & mut ( ) ) ; ) *
143146
144- buf = bridge. dispatch. call( buf) ;
147+ buf = match & mut bridge. dispatch {
148+ DispatchWay :: Closure ( f) => f. call( buf) ,
149+ DispatchWay :: Directly ( disp) => disp. dispatch( buf) ,
150+ } ;
145151
146152 let r = Result :: <_, PanicMessage >:: decode( & mut & buf[ ..] , & mut ( ) ) ;
147153
@@ -155,13 +161,18 @@ macro_rules! define_client_side {
155161}
156162with_api ! ( self , self , define_client_side) ;
157163
164+ enum DispatchWay < ' a > {
165+ Closure ( closure:: Closure < ' a , Buffer , Buffer > ) ,
166+ Directly ( Dispatcher < NoRustc > ) ,
167+ }
168+
158169struct Bridge < ' a > {
159170 /// Reusable buffer (only `clear`-ed, never shrunk), primarily
160171 /// used for making requests.
161172 cached_buffer : Buffer ,
162173
163174 /// Server-side function that the client uses to make requests.
164- dispatch : closure :: Closure < ' a , Buffer , Buffer > ,
175+ dispatch : DispatchWay < ' a > ,
165176
166177 /// Provided globals for this macro expansion.
167178 globals : ExpnGlobals < Span > ,
@@ -173,12 +184,33 @@ impl<'a> !Sync for Bridge<'a> {}
173184#[ allow( unsafe_code) ]
174185mod state {
175186 use std:: cell:: { Cell , RefCell } ;
187+ use std:: marker:: PhantomData ;
176188 use std:: ptr;
177189
178190 use super :: Bridge ;
191+ use crate :: StandaloneLevel ;
192+ use crate :: bridge:: buffer:: Buffer ;
193+ use crate :: bridge:: client:: { COUNTERS , DispatchWay } ;
194+ use crate :: bridge:: server:: { Dispatcher , HandleStore , MarkedTypes } ;
195+ use crate :: bridge:: { ExpnGlobals , Marked , standalone} ;
179196
180197 thread_local ! {
181198 static BRIDGE_STATE : Cell <* const ( ) > = const { Cell :: new( ptr:: null( ) ) } ;
199+ static STANDALONE : RefCell <Bridge <' static >> = RefCell :: new( standalone_bridge( ) ) ;
200+ pub ( super ) static USE_STANDALONE : Cell <StandaloneLevel > = const { Cell :: new( StandaloneLevel :: Never ) } ;
201+ }
202+
203+ fn standalone_bridge ( ) -> Bridge < ' static > {
204+ let mut store = HandleStore :: new ( & COUNTERS ) ;
205+ let id = store. Span . alloc ( Marked { value : standalone:: Span :: DUMMY , _marker : PhantomData } ) ;
206+ let dummy = super :: Span { handle : id } ;
207+ let dispatcher =
208+ Dispatcher { handle_store : store, server : MarkedTypes ( standalone:: NoRustc ) } ;
209+ Bridge {
210+ cached_buffer : Buffer :: new ( ) ,
211+ dispatch : DispatchWay :: Directly ( dispatcher) ,
212+ globals : ExpnGlobals { call_site : dummy, def_site : dummy, mixed_site : dummy } ,
213+ }
182214 }
183215
184216 pub ( super ) fn set < ' bridge , R > ( state : & RefCell < Bridge < ' bridge > > , f : impl FnOnce ( ) -> R ) -> R {
@@ -199,16 +231,23 @@ mod state {
199231 pub ( super ) fn with < R > (
200232 f : impl for < ' bridge > FnOnce ( Option < & RefCell < Bridge < ' bridge > > > ) -> R ,
201233 ) -> R {
202- let state = BRIDGE_STATE . get ( ) ;
203- // SAFETY: the only place where the pointer is set is in `set`. It puts
204- // back the previous value after the inner call has returned, so we know
205- // that as long as the pointer is not null, it came from a reference to
206- // a `RefCell<Bridge>` that outlasts the call to this function. Since `f`
207- // works the same for any lifetime of the bridge, including the actual
208- // one, we can lie here and say that the lifetime is `'static` without
209- // anyone noticing.
210- let bridge = unsafe { state. cast :: < RefCell < Bridge < ' static > > > ( ) . as_ref ( ) } ;
211- f ( bridge)
234+ let level = USE_STANDALONE . get ( ) ;
235+ if level == StandaloneLevel :: Always
236+ || ( level == StandaloneLevel :: FallbackOnly && BRIDGE_STATE . get ( ) . is_null ( ) )
237+ {
238+ STANDALONE . with ( |bridge| f ( Some ( bridge) ) )
239+ } else {
240+ let state = BRIDGE_STATE . get ( ) ;
241+ // SAFETY: the only place where the pointer is set is in `set`. It puts
242+ // back the previous value after the inner call has returned, so we know
243+ // that as long as the pointer is not null, it came from a reference to
244+ // a `RefCell<Bridge>` that outlasts the call to this function. Since `f`
245+ // works the same for any lifetime of the bridge, including the actual
246+ // one, we can lie here and say that the lifetime is `'static` without
247+ // anyone noticing.
248+ let bridge = unsafe { state. cast :: < RefCell < Bridge < ' static > > > ( ) . as_ref ( ) } ;
249+ f ( bridge)
250+ }
212251 }
213252}
214253
@@ -228,6 +267,10 @@ pub(crate) fn is_available() -> bool {
228267 state:: with ( |s| s. is_some ( ) )
229268}
230269
270+ pub ( crate ) fn enable_standalone ( level : StandaloneLevel ) {
271+ state:: USE_STANDALONE . set ( level) ;
272+ }
273+
231274/// A client-side RPC entry-point, which may be using a different `proc_macro`
232275/// from the one used by the server, but can be invoked compatibly.
233276///
@@ -292,7 +335,11 @@ fn run_client<A: for<'a, 's> Decode<'a, 's, ()>, R: Encode<()>>(
292335 let ( globals, input) = <( ExpnGlobals < Span > , A ) >:: decode ( reader, & mut ( ) ) ;
293336
294337 // Put the buffer we used for input back in the `Bridge` for requests.
295- let state = RefCell :: new ( Bridge { cached_buffer : buf. take ( ) , dispatch, globals } ) ;
338+ let state = RefCell :: new ( Bridge {
339+ cached_buffer : buf. take ( ) ,
340+ dispatch : DispatchWay :: Closure ( dispatch) ,
341+ globals,
342+ } ) ;
296343
297344 let output = state:: set ( & state, || f ( input) ) ;
298345
0 commit comments