5 macro_rules
! define_handles
{
7 'owned
: $
($oty
:ident
,)*
8 'interned
: $
($ity
:ident
,)*
11 #[allow(non_snake_case)]
12 pub struct HandleCounters
{
13 $
($oty
: AtomicUsize
,)*
14 $
($ity
: AtomicUsize
,)*
18 // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
19 // a wrapper `fn` pointer, once `const fn` can reference `static`s.
20 extern "C" fn get() -> &'
static Self {
21 static COUNTERS
: HandleCounters
= HandleCounters
{
22 $
($oty
: AtomicUsize
::new(1),)*
23 $
($ity
: AtomicUsize
::new(1),)*
29 // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`.
31 #[allow(non_snake_case)]
32 pub(super) struct HandleStore
<S
: server
::Types
> {
33 $
($oty
: handle
::OwnedStore
<S
::$oty
>,)*
34 $
($ity
: handle
::InternedStore
<S
::$ity
>,)*
37 impl<S
: server
::Types
> HandleStore
<S
> {
38 pub(super) fn new(handle_counters
: &'
static HandleCounters
) -> Self {
40 $
($oty
: handle
::OwnedStore
::new(&handle_counters
.$oty
),)*
41 $
($ity
: handle
::InternedStore
::new(&handle_counters
.$ity
),)*
48 pub(crate) struct $
oty(handle
::Handle
);
49 impl !Send
for $oty {}
50 impl !Sync
for $oty {}
52 // Forward `Drop::drop` to the inherent `drop` method.
59 impl<S
> Encode
<S
> for $oty
{
60 fn encode(self, w
: &mut Writer
, s
: &mut S
) {
67 impl<S
: server
::Types
> DecodeMut
<'_
, '_
, HandleStore
<server
::MarkedTypes
<S
>>>
68 for Marked
<S
::$oty
, $oty
>
70 fn decode(r
: &mut Reader
<'_
>, s
: &mut HandleStore
<server
::MarkedTypes
<S
>>) -> Self {
71 s
.$oty
.take(handle
::Handle
::decode(r
, &mut ()))
75 impl<S
> Encode
<S
> for &$oty
{
76 fn encode(self, w
: &mut Writer
, s
: &mut S
) {
81 impl<'s
, S
: server
::Types
> Decode
<'_
, 's
, HandleStore
<server
::MarkedTypes
<S
>>>
82 for &'s Marked
<S
::$oty
, $oty
>
84 fn decode(r
: &mut Reader
<'_
>, s
: &'s HandleStore
<server
::MarkedTypes
<S
>>) -> Self {
85 &s
.$oty
[handle
::Handle
::decode(r
, &mut ())]
89 impl<S
> Encode
<S
> for &mut $oty
{
90 fn encode(self, w
: &mut Writer
, s
: &mut S
) {
95 impl<'s
, S
: server
::Types
> DecodeMut
<'_
, 's
, HandleStore
<server
::MarkedTypes
<S
>>>
96 for &'s
mut Marked
<S
::$oty
, $oty
>
100 s
: &'s
mut HandleStore
<server
::MarkedTypes
<S
>>
102 &mut s
.$oty
[handle
::Handle
::decode(r
, &mut ())]
106 impl<S
: server
::Types
> Encode
<HandleStore
<server
::MarkedTypes
<S
>>>
107 for Marked
<S
::$oty
, $oty
>
109 fn encode(self, w
: &mut Writer
, s
: &mut HandleStore
<server
::MarkedTypes
<S
>>) {
110 s
.$oty
.alloc(self).encode(w
, s
);
114 impl<S
> DecodeMut
<'_
, '_
, S
> for $oty
{
115 fn decode(r
: &mut Reader
<'_
>, s
: &mut S
) -> Self {
116 $
oty(handle
::Handle
::decode(r
, s
))
123 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
124 pub(crate) struct $
ity(handle
::Handle
);
125 impl !Send
for $ity {}
126 impl !Sync
for $ity {}
128 impl<S
> Encode
<S
> for $ity
{
129 fn encode(self, w
: &mut Writer
, s
: &mut S
) {
134 impl<S
: server
::Types
> DecodeMut
<'_
, '_
, HandleStore
<server
::MarkedTypes
<S
>>>
135 for Marked
<S
::$ity
, $ity
>
137 fn decode(r
: &mut Reader
<'_
>, s
: &mut HandleStore
<server
::MarkedTypes
<S
>>) -> Self {
138 s
.$ity
.copy(handle
::Handle
::decode(r
, &mut ()))
142 impl<S
: server
::Types
> Encode
<HandleStore
<server
::MarkedTypes
<S
>>>
143 for Marked
<S
::$ity
, $ity
>
145 fn encode(self, w
: &mut Writer
, s
: &mut HandleStore
<server
::MarkedTypes
<S
>>) {
146 s
.$ity
.alloc(self).encode(w
, s
);
150 impl<S
> DecodeMut
<'_
, '_
, S
> for $ity
{
151 fn decode(r
: &mut Reader
<'_
>, s
: &mut S
) -> Self {
152 $
ity(handle
::Handle
::decode(r
, s
))
176 // FIXME(eddyb) generate these impls by pattern-matching on the
177 // names of methods - also could use the presence of `fn drop`
178 // to distinguish between 'owned and 'interned, above.
179 // Alternatively, special 'modes" could be listed of types in with_api
180 // instead of pattern matching on methods, here and in server decl.
182 impl Clone
for TokenStream
{
183 fn clone(&self) -> Self {
188 impl Clone
for TokenStreamIter
{
189 fn clone(&self) -> Self {
194 impl Clone
for Group
{
195 fn clone(&self) -> Self {
200 impl Clone
for Literal
{
201 fn clone(&self) -> Self {
206 impl fmt
::Debug
for Literal
{
207 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
208 f
.debug_struct("Literal")
209 // format the kind without quotes, as in `kind: Float`
210 .field("kind", &format_args
!("{}", &self.debug_kind()))
211 .field("symbol", &self.symbol())
212 // format `Some("...")` on one line even in {:#?} mode
213 .field("suffix", &format_args
!("{:?}", &self.suffix()))
214 .field("span", &self.span())
219 impl Clone
for SourceFile
{
220 fn clone(&self) -> Self {
225 impl fmt
::Debug
for Span
{
226 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
227 f
.write_str(&self.debug())
231 macro_rules
! define_client_side
{
233 $
(fn $method
:ident($
($arg
:ident
: $arg_ty
:ty
),* $
(,)?
) $
(-> $ret_ty
:ty
)*;)*
236 $
(pub(crate) fn $
method($
($arg
: $arg_ty
),*) $
(-> $ret_ty
)* {
237 Bridge
::with(|bridge
| {
238 let mut b
= bridge
.cached_buffer
.take();
241 api_tags
::Method
::$
name(api_tags
::$name
::$method
).encode(&mut b
, &mut ());
242 reverse_encode
!(b
; $
($arg
),*);
244 b
= bridge
.dispatch
.call(b
);
246 let r
= Result
::<_
, PanicMessage
>::decode(&mut &b
[..], &mut ());
248 bridge
.cached_buffer
= b
;
250 r
.unwrap_or_else(|e
| panic
::resume_unwind(e
.into()))
256 with_api
!(self, self, define_client_side
);
258 enum BridgeState
<'a
> {
259 /// No server is currently connected to this client.
262 /// A server is connected and available for requests.
263 Connected(Bridge
<'a
>),
265 /// Access to the bridge is being exclusively acquired
266 /// (e.g., during `BridgeState::with`).
272 impl<'a
> scoped_cell
::ApplyL
<'a
> for BridgeStateL
{
273 type Out
= BridgeState
<'a
>;
277 static BRIDGE_STATE
: scoped_cell
::ScopedCell
<BridgeStateL
> =
278 scoped_cell
::ScopedCell
::new(BridgeState
::NotConnected
);
281 impl BridgeState
<'_
> {
282 /// Take exclusive control of the thread-local
283 /// `BridgeState`, and pass it to `f`, mutably.
284 /// The state will be restored after `f` exits, even
285 /// by panic, including modifications made to it by `f`.
287 /// N.B., while `f` is running, the thread-local state
288 /// is `BridgeState::InUse`.
289 fn with
<R
>(f
: impl FnOnce(&mut BridgeState
<'_
>) -> R
) -> R
{
290 BRIDGE_STATE
.with(|state
| {
291 state
.replace(BridgeState
::InUse
, |mut state
| {
292 // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone
300 pub(crate) fn is_available() -> bool
{
301 BridgeState
::with(|state
| match state
{
302 BridgeState
::Connected(_
) | BridgeState
::InUse
=> true,
303 BridgeState
::NotConnected
=> false,
307 fn enter
<R
>(self, f
: impl FnOnce() -> R
) -> R
{
308 let force_show_panics
= self.force_show_panics
;
309 // Hide the default panic output within `proc_macro` expansions.
310 // NB. the server can't do this because it may use a different libstd.
311 static HIDE_PANICS_DURING_EXPANSION
: Once
= Once
::new();
312 HIDE_PANICS_DURING_EXPANSION
.call_once(|| {
313 panic
::update_hook(move |prev
, info
| {
314 let show
= BridgeState
::with(|state
| match state
{
315 BridgeState
::NotConnected
=> true,
316 BridgeState
::Connected(_
) | BridgeState
::InUse
=> force_show_panics
,
324 BRIDGE_STATE
.with(|state
| state
.set(BridgeState
::Connected(self), f
))
327 fn with
<R
>(f
: impl FnOnce(&mut Bridge
<'_
>) -> R
) -> R
{
328 BridgeState
::with(|state
| match state
{
329 BridgeState
::NotConnected
=> {
330 panic
!("procedural macro API is used outside of a procedural macro");
332 BridgeState
::InUse
=> {
333 panic
!("procedural macro API is used while it's already in use");
335 BridgeState
::Connected(bridge
) => f(bridge
),
340 /// A client-side "global object" (usually a function pointer),
341 /// which may be using a different `proc_macro` from the one
342 /// used by the server, but can be interacted with compatibly.
344 /// N.B., `F` must have FFI-friendly memory layout (e.g., a pointer).
345 /// The call ABI of function pointers used for `F` doesn't
346 /// need to match between server and client, since it's only
347 /// passed between them and (eventually) called by the client.
349 #[derive(Copy, Clone)]
350 pub struct Client
<F
> {
351 // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
352 // a wrapper `fn` pointer, once `const fn` can reference `static`s.
353 pub(super) get_handle_counters
: extern "C" fn() -> &'
static HandleCounters
,
354 pub(super) run
: extern "C" fn(Bridge
<'_
>, F
) -> Buffer
<u8>,
358 /// Client-side helper for handling client panics, entering the bridge,
359 /// deserializing input and serializing output.
360 // FIXME(eddyb) maybe replace `Bridge::enter` with this?
361 fn run_client
<A
: for<'a
, 's
> DecodeMut
<'a
, 's
, ()>, R
: Encode
<()>>(
362 mut bridge
: Bridge
<'_
>,
363 f
: impl FnOnce(A
) -> R
,
365 // The initial `cached_buffer` contains the input.
366 let mut b
= bridge
.cached_buffer
.take();
368 panic
::catch_unwind(panic
::AssertUnwindSafe(|| {
370 let reader
= &mut &b
[..];
371 let input
= A
::decode(reader
, &mut ());
373 // Put the `cached_buffer` back in the `Bridge`, for requests.
374 Bridge
::with(|bridge
| bridge
.cached_buffer
= b
.take());
376 let output
= f(input
);
378 // Take the `cached_buffer` back out, for the output value.
379 b
= Bridge
::with(|bridge
| bridge
.cached_buffer
.take());
381 // HACK(eddyb) Separate encoding a success value (`Ok(output)`)
382 // from encoding a panic (`Err(e: PanicMessage)`) to avoid
383 // having handles outside the `bridge.enter(|| ...)` scope, and
384 // to catch panics that could happen while encoding the success.
386 // Note that panics should be impossible beyond this point, but
387 // this is defensively trying to avoid any accidental panicking
388 // reaching the `extern "C"` (which should `abort` but might not
389 // at the moment, so this is also potentially preventing UB).
391 Ok
::<_
, ()>(output
).encode(&mut b
, &mut ());
394 .map_err(PanicMessage
::from
)
395 .unwrap_or_else(|e
| {
397 Err
::<(), _
>(e
).encode(&mut b
, &mut ());
402 impl Client
<fn(crate::TokenStream
) -> crate::TokenStream
> {
403 #[rustc_allow_const_fn_unstable(const_fn)]
404 pub const fn expand1(f
: fn(crate::TokenStream
) -> crate::TokenStream
) -> Self {
407 f
: impl FnOnce(crate::TokenStream
) -> crate::TokenStream
,
409 run_client(bridge
, |input
| f(crate::TokenStream(input
)).0)
411 Client { get_handle_counters: HandleCounters::get, run, f }
415 impl Client
<fn(crate::TokenStream
, crate::TokenStream
) -> crate::TokenStream
> {
416 #[rustc_allow_const_fn_unstable(const_fn)]
417 pub const fn expand2(
418 f
: fn(crate::TokenStream
, crate::TokenStream
) -> crate::TokenStream
,
422 f
: impl FnOnce(crate::TokenStream
, crate::TokenStream
) -> crate::TokenStream
,
424 run_client(bridge
, |(input
, input2
)| {
425 f(crate::TokenStream(input
), crate::TokenStream(input2
)).0
428 Client { get_handle_counters: HandleCounters::get, run, f }
433 #[derive(Copy, Clone)]
436 trait_name
: &'
static str,
437 attributes
: &'
static [&'
static str],
438 client
: Client
<fn(crate::TokenStream
) -> crate::TokenStream
>,
443 client
: Client
<fn(crate::TokenStream
, crate::TokenStream
) -> crate::TokenStream
>,
448 client
: Client
<fn(crate::TokenStream
) -> crate::TokenStream
>,
453 pub fn name(&self) -> &'
static str {
455 ProcMacro
::CustomDerive { trait_name, .. }
=> trait_name
,
456 ProcMacro
::Attr { name, .. }
=> name
,
457 ProcMacro
::Bang { name, .. }
=> name
,
461 #[rustc_allow_const_fn_unstable(const_fn)]
462 pub const fn custom_derive(
463 trait_name
: &'
static str,
464 attributes
: &'
static [&'
static str],
465 expand
: fn(crate::TokenStream
) -> crate::TokenStream
,
467 ProcMacro
::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
470 #[rustc_allow_const_fn_unstable(const_fn)]
473 expand
: fn(crate::TokenStream
, crate::TokenStream
) -> crate::TokenStream
,
475 ProcMacro
::Attr { name, client: Client::expand2(expand) }
478 #[rustc_allow_const_fn_unstable(const_fn)]
481 expand
: fn(crate::TokenStream
) -> crate::TokenStream
,
483 ProcMacro
::Bang { name, client: Client::expand1(expand) }