5 use std
::marker
::PhantomData
;
7 macro_rules
! define_handles
{
9 'owned
: $
($oty
:ident
,)*
10 'interned
: $
($ity
:ident
,)*
13 #[allow(non_snake_case)]
14 pub struct HandleCounters
{
15 $
($oty
: AtomicUsize
,)*
16 $
($ity
: AtomicUsize
,)*
20 // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
21 // a wrapper `fn` pointer, once `const fn` can reference `static`s.
22 extern "C" fn get() -> &'
static Self {
23 static COUNTERS
: HandleCounters
= HandleCounters
{
24 $
($oty
: AtomicUsize
::new(1),)*
25 $
($ity
: AtomicUsize
::new(1),)*
31 // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
32 #[allow(non_snake_case)]
33 pub(super) struct HandleStore
<S
: server
::Types
> {
34 $
($oty
: handle
::OwnedStore
<S
::$oty
>,)*
35 $
($ity
: handle
::InternedStore
<S
::$ity
>,)*
38 impl<S
: server
::Types
> HandleStore
<S
> {
39 pub(super) fn new(handle_counters
: &'
static HandleCounters
) -> Self {
41 $
($oty
: handle
::OwnedStore
::new(&handle_counters
.$oty
),)*
42 $
($ity
: handle
::InternedStore
::new(&handle_counters
.$ity
),)*
48 pub(crate) struct $oty
{
49 handle
: handle
::Handle
,
50 // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual
51 // way of doing this, but that requires unstable features.
52 // rust-analyzer uses this code and avoids unstable features.
53 _marker
: PhantomData
<*mut ()>,
56 // Forward `Drop::drop` to the inherent `drop` method.
66 impl<S
> Encode
<S
> for $oty
{
67 fn encode(self, w
: &mut Writer
, s
: &mut S
) {
68 let handle
= self.handle
;
74 impl<S
: server
::Types
> DecodeMut
<'_
, '_
, HandleStore
<server
::MarkedTypes
<S
>>>
75 for Marked
<S
::$oty
, $oty
>
77 fn decode(r
: &mut Reader
<'_
>, s
: &mut HandleStore
<server
::MarkedTypes
<S
>>) -> Self {
78 s
.$oty
.take(handle
::Handle
::decode(r
, &mut ()))
82 impl<S
> Encode
<S
> for &$oty
{
83 fn encode(self, w
: &mut Writer
, s
: &mut S
) {
84 self.handle
.encode(w
, s
);
88 impl<'s
, S
: server
::Types
> Decode
<'_
, 's
, HandleStore
<server
::MarkedTypes
<S
>>>
89 for &'s Marked
<S
::$oty
, $oty
>
91 fn decode(r
: &mut Reader
<'_
>, s
: &'s HandleStore
<server
::MarkedTypes
<S
>>) -> Self {
92 &s
.$oty
[handle
::Handle
::decode(r
, &mut ())]
96 impl<S
> Encode
<S
> for &mut $oty
{
97 fn encode(self, w
: &mut Writer
, s
: &mut S
) {
98 self.handle
.encode(w
, s
);
102 impl<'s
, S
: server
::Types
> DecodeMut
<'_
, 's
, HandleStore
<server
::MarkedTypes
<S
>>>
103 for &'s
mut Marked
<S
::$oty
, $oty
>
107 s
: &'s
mut HandleStore
<server
::MarkedTypes
<S
>>
109 &mut s
.$oty
[handle
::Handle
::decode(r
, &mut ())]
113 impl<S
: server
::Types
> Encode
<HandleStore
<server
::MarkedTypes
<S
>>>
114 for Marked
<S
::$oty
, $oty
>
116 fn encode(self, w
: &mut Writer
, s
: &mut HandleStore
<server
::MarkedTypes
<S
>>) {
117 s
.$oty
.alloc(self).encode(w
, s
);
121 impl<S
> DecodeMut
<'_
, '_
, S
> for $oty
{
122 fn decode(r
: &mut Reader
<'_
>, s
: &mut S
) -> Self {
124 handle
: handle
::Handle
::decode(r
, s
),
125 _marker
: PhantomData
,
132 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
133 pub(crate) struct $ity
{
134 handle
: handle
::Handle
,
135 // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual
136 // way of doing this, but that requires unstable features.
137 // rust-analyzer uses this code and avoids unstable features.
138 _marker
: PhantomData
<*mut ()>,
141 impl<S
> Encode
<S
> for $ity
{
142 fn encode(self, w
: &mut Writer
, s
: &mut S
) {
143 self.handle
.encode(w
, s
);
147 impl<S
: server
::Types
> DecodeMut
<'_
, '_
, HandleStore
<server
::MarkedTypes
<S
>>>
148 for Marked
<S
::$ity
, $ity
>
150 fn decode(r
: &mut Reader
<'_
>, s
: &mut HandleStore
<server
::MarkedTypes
<S
>>) -> Self {
151 s
.$ity
.copy(handle
::Handle
::decode(r
, &mut ()))
155 impl<S
: server
::Types
> Encode
<HandleStore
<server
::MarkedTypes
<S
>>>
156 for Marked
<S
::$ity
, $ity
>
158 fn encode(self, w
: &mut Writer
, s
: &mut HandleStore
<server
::MarkedTypes
<S
>>) {
159 s
.$ity
.alloc(self).encode(w
, s
);
163 impl<S
> DecodeMut
<'_
, '_
, S
> for $ity
{
164 fn decode(r
: &mut Reader
<'_
>, s
: &mut S
) -> Self {
166 handle
: handle
::Handle
::decode(r
, s
),
167 _marker
: PhantomData
,
190 // FIXME(eddyb) generate these impls by pattern-matching on the
191 // names of methods - also could use the presence of `fn drop`
192 // to distinguish between 'owned and 'interned, above.
193 // Alternatively, special "modes" could be listed of types in with_api
194 // instead of pattern matching on methods, here and in server decl.
196 impl Clone
for TokenStream
{
197 fn clone(&self) -> Self {
202 impl Clone
for Group
{
203 fn clone(&self) -> Self {
208 impl Clone
for Literal
{
209 fn clone(&self) -> Self {
214 impl fmt
::Debug
for Literal
{
215 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
216 f
.debug_struct("Literal")
217 // format the kind without quotes, as in `kind: Float`
218 .field("kind", &format_args
!("{}", &self.debug_kind()))
219 .field("symbol", &self.symbol())
220 // format `Some("...")` on one line even in {:#?} mode
221 .field("suffix", &format_args
!("{:?}", &self.suffix()))
222 .field("span", &self.span())
227 impl Clone
for SourceFile
{
228 fn clone(&self) -> Self {
233 impl fmt
::Debug
for Span
{
234 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
235 f
.write_str(&self.debug())
239 macro_rules
! define_client_side
{
241 $
(fn $method
:ident($
($arg
:ident
: $arg_ty
:ty
),* $
(,)?
) $
(-> $ret_ty
:ty
)*;)*
244 $
(pub(crate) fn $
method($
($arg
: $arg_ty
),*) $
(-> $ret_ty
)* {
245 Bridge
::with(|bridge
| {
246 let mut buf
= bridge
.cached_buffer
.take();
249 api_tags
::Method
::$
name(api_tags
::$name
::$method
).encode(&mut buf
, &mut ());
250 reverse_encode
!(buf
; $
($arg
),*);
252 buf
= bridge
.dispatch
.call(buf
);
254 let r
= Result
::<_
, PanicMessage
>::decode(&mut &buf
[..], &mut ());
256 bridge
.cached_buffer
= buf
;
258 r
.unwrap_or_else(|e
| panic
::resume_unwind(e
.into()))
264 with_api
!(self, self, define_client_side
);
266 enum BridgeState
<'a
> {
267 /// No server is currently connected to this client.
270 /// A server is connected and available for requests.
271 Connected(Bridge
<'a
>),
273 /// Access to the bridge is being exclusively acquired
274 /// (e.g., during `BridgeState::with`).
280 impl<'a
> scoped_cell
::ApplyL
<'a
> for BridgeStateL
{
281 type Out
= BridgeState
<'a
>;
285 static BRIDGE_STATE
: scoped_cell
::ScopedCell
<BridgeStateL
> =
286 scoped_cell
::ScopedCell
::new(BridgeState
::NotConnected
);
289 impl BridgeState
<'_
> {
290 /// Take exclusive control of the thread-local
291 /// `BridgeState`, and pass it to `f`, mutably.
292 /// The state will be restored after `f` exits, even
293 /// by panic, including modifications made to it by `f`.
295 /// N.B., while `f` is running, the thread-local state
296 /// is `BridgeState::InUse`.
297 fn with
<R
>(f
: impl FnOnce(&mut BridgeState
<'_
>) -> R
) -> R
{
298 BRIDGE_STATE
.with(|state
| {
299 state
.replace(BridgeState
::InUse
, |mut state
| {
300 // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone
308 pub(crate) fn is_available() -> bool
{
309 BridgeState
::with(|state
| match state
{
310 BridgeState
::Connected(_
) | BridgeState
::InUse
=> true,
311 BridgeState
::NotConnected
=> false,
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
,
333 BRIDGE_STATE
.with(|state
| state
.set(BridgeState
::Connected(self), f
))
336 fn with
<R
>(f
: impl FnOnce(&mut Bridge
<'_
>) -> R
) -> R
{
337 BridgeState
::with(|state
| match state
{
338 BridgeState
::NotConnected
=> {
339 panic
!("procedural macro API is used outside of a procedural macro");
341 BridgeState
::InUse
=> {
342 panic
!("procedural macro API is used while it's already in use");
344 BridgeState
::Connected(bridge
) => f(bridge
),
349 /// A client-side RPC entry-point, which may be using a different `proc_macro`
350 /// from the one used by the server, but can be invoked compatibly.
352 /// Note that the (phantom) `I` ("input") and `O` ("output") type parameters
353 /// decorate the `Client<I, O>` with the RPC "interface" of the entry-point, but
354 /// do not themselves participate in ABI, at all, only facilitate type-checking.
356 /// E.g. `Client<TokenStream, TokenStream>` is the common proc macro interface,
357 /// used for `#[proc_macro] fn foo(input: TokenStream) -> TokenStream`,
358 /// indicating that the RPC input and output will be serialized token streams,
359 /// and forcing the use of APIs that take/return `S::TokenStream`, server-side.
361 pub struct Client
<I
, O
> {
362 // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
363 // a wrapper `fn` pointer, once `const fn` can reference `static`s.
364 pub(super) get_handle_counters
: extern "C" fn() -> &'
static HandleCounters
,
366 pub(super) run
: extern "C" fn(Bridge
<'_
>) -> Buffer
,
368 pub(super) _marker
: PhantomData
<fn(I
) -> O
>,
371 impl<I
, O
> Copy
for Client
<I
, O
> {}
372 impl<I
, O
> Clone
for Client
<I
, O
> {
373 fn clone(&self) -> Self {
378 /// Client-side helper for handling client panics, entering the bridge,
379 /// deserializing input and serializing output.
380 // FIXME(eddyb) maybe replace `Bridge::enter` with this?
381 fn run_client
<A
: for<'a
, 's
> DecodeMut
<'a
, 's
, ()>, R
: Encode
<()>>(
382 mut bridge
: Bridge
<'_
>,
383 f
: impl FnOnce(A
) -> R
,
385 // The initial `cached_buffer` contains the input.
386 let mut buf
= bridge
.cached_buffer
.take();
388 panic
::catch_unwind(panic
::AssertUnwindSafe(|| {
390 let reader
= &mut &buf
[..];
391 let input
= A
::decode(reader
, &mut ());
393 // Put the `cached_buffer` back in the `Bridge`, for requests.
394 Bridge
::with(|bridge
| bridge
.cached_buffer
= buf
.take());
396 let output
= f(input
);
398 // Take the `cached_buffer` back out, for the output value.
399 buf
= Bridge
::with(|bridge
| bridge
.cached_buffer
.take());
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.
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).
411 Ok
::<_
, ()>(output
).encode(&mut buf
, &mut ());
414 .map_err(PanicMessage
::from
)
415 .unwrap_or_else(|e
| {
417 Err
::<(), _
>(e
).encode(&mut buf
, &mut ());
422 impl Client
<crate::TokenStream
, crate::TokenStream
> {
423 pub const fn expand1(f
: impl Fn(crate::TokenStream
) -> crate::TokenStream
+ Copy
) -> Self {
425 get_handle_counters
: HandleCounters
::get
,
426 run
: super::selfless_reify
::reify_to_extern_c_fn_hrt_bridge(move |bridge
| {
427 run_client(bridge
, |input
| f(crate::TokenStream(Some(input
))).0)
429 _marker
: PhantomData
,
434 impl Client
<(crate::TokenStream
, crate::TokenStream
), crate::TokenStream
> {
435 pub const fn expand2(
436 f
: impl Fn(crate::TokenStream
, crate::TokenStream
) -> crate::TokenStream
+ Copy
,
439 get_handle_counters
: HandleCounters
::get
,
440 run
: super::selfless_reify
::reify_to_extern_c_fn_hrt_bridge(move |bridge
| {
441 run_client(bridge
, |(input
, input2
)| {
442 f(crate::TokenStream(Some(input
)), crate::TokenStream(Some(input2
))).0
445 _marker
: PhantomData
,
451 #[derive(Copy, Clone)]
454 trait_name
: &'
static str,
455 attributes
: &'
static [&'
static str],
456 client
: Client
<crate::TokenStream
, crate::TokenStream
>,
461 client
: Client
<(crate::TokenStream
, crate::TokenStream
), crate::TokenStream
>,
466 client
: Client
<crate::TokenStream
, crate::TokenStream
>,
471 pub fn name(&self) -> &'
static str {
473 ProcMacro
::CustomDerive { trait_name, .. }
=> trait_name
,
474 ProcMacro
::Attr { name, .. }
=> name
,
475 ProcMacro
::Bang { name, .. }
=> name
,
479 pub const fn custom_derive(
480 trait_name
: &'
static str,
481 attributes
: &'
static [&'
static str],
482 expand
: impl Fn(crate::TokenStream
) -> crate::TokenStream
+ Copy
,
484 ProcMacro
::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
489 expand
: impl Fn(crate::TokenStream
, crate::TokenStream
) -> crate::TokenStream
+ Copy
,
491 ProcMacro
::Attr { name, client: Client::expand2(expand) }
496 expand
: impl Fn(crate::TokenStream
) -> crate::TokenStream
+ Copy
,
498 ProcMacro
::Bang { name, client: Client::expand1(expand) }