Skip to content

Commit

Permalink
proc_macro/bridge: remove Closure.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed May 14, 2022
1 parent 4689fbe commit 9242c12
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 67 deletions.
69 changes: 43 additions & 26 deletions library/proc_macro/src/bridge/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use super::*;

use std::cell::Cell;
use std::marker::PhantomData;

macro_rules! define_handles {
Expand Down Expand Up @@ -256,7 +257,7 @@ macro_rules! define_client_side {
api_tags::Method::$name(api_tags::$name::$method).encode(&mut b, &mut ());
reverse_encode!(b; $($arg),*);

b = bridge.dispatch.call(b);
b = (bridge.dispatch)(b);

let r = Result::<_, PanicMessage>::decode(&mut &b[..], &mut ());

Expand All @@ -270,48 +271,64 @@ macro_rules! define_client_side {
}
with_api!(self, self, define_client_side);

enum BridgeState<'a> {
enum BridgeState {
/// No server is currently connected to this client.
NotConnected,

/// A server is connected and available for requests.
Connected(Bridge<'a>),
Connected(Bridge),

/// Access to the bridge is being exclusively acquired
/// (e.g., during `BridgeState::with`).
InUse,
}

enum BridgeStateL {}
impl BridgeState {
/// Sets the thread-local `BridgeState` to `replacement` while
/// running `f`, which gets the old `BridgeState`, mutably.
///
/// The state will be restored after `f` exits, even
/// by panic, including modifications made to it by `f`.
fn replace_during<R>(replacement: Self, f: impl FnOnce(&mut Self) -> R) -> R {
/// Wrapper that ensures that a cell always gets filled
/// (with the original state, optionally changed by `f`),
/// even if `f` had panicked.
struct PutBackOnDrop<'a, T> {
cell: &'a Cell<T>,
value: Option<T>,
}

impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL {
type Out = BridgeState<'a>;
}
impl<'a, T> Drop for PutBackOnDrop<'a, T> {
fn drop(&mut self) {
self.cell.set(self.value.take().unwrap());
}
}

thread_local! {
static BRIDGE_STATE: scoped_cell::ScopedCell<BridgeStateL> =
scoped_cell::ScopedCell::new(BridgeState::NotConnected);
}
thread_local! {
static BRIDGE_STATE: Cell<BridgeState> = Cell::new(BridgeState::NotConnected);
}
BRIDGE_STATE.with(|state| {
let mut put_back_on_drop =
PutBackOnDrop { cell: state, value: Some(state.replace(replacement)) };

f(put_back_on_drop.value.as_mut().unwrap())
})
}

impl BridgeState<'_> {
/// Take exclusive control of the thread-local
/// `BridgeState`, and pass it to `f`, mutably.
///
/// The state will be restored after `f` exits, even
/// by panic, including modifications made to it by `f`.
///
/// N.B., while `f` is running, the thread-local state
/// is `BridgeState::InUse`.
fn with<R>(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R {
BRIDGE_STATE.with(|state| {
state.replace(BridgeState::InUse, |mut state| {
// FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone
f(&mut *state)
})
})
fn with<R>(f: impl FnOnce(&mut Self) -> R) -> R {
Self::replace_during(BridgeState::InUse, f)
}
}

impl Bridge<'_> {
impl Bridge {
pub(crate) fn is_available() -> bool {
BridgeState::with(|state| match state {
BridgeState::Connected(_) | BridgeState::InUse => true,
Expand All @@ -337,10 +354,10 @@ impl Bridge<'_> {
}));
});

BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f))
BridgeState::replace_during(BridgeState::Connected(self), |_| f())
}

fn with<R>(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R {
fn with<R>(f: impl FnOnce(&mut Self) -> R) -> R {
BridgeState::with(|state| match state {
BridgeState::NotConnected => {
panic!("procedural macro API is used outside of a procedural macro");
Expand All @@ -367,15 +384,15 @@ pub struct Client<F> {
// FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
// a wrapper `fn` pointer, once `const fn` can reference `static`s.
pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters,
pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer<u8>,
pub(super) run: extern "C" fn(Bridge, F) -> Buffer<u8>,
pub(super) f: F,
}

/// Client-side helper for handling client panics, entering the bridge,
/// deserializing input and serializing output.
// FIXME(eddyb) maybe replace `Bridge::enter` with this?
fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
mut bridge: Bridge<'_>,
mut bridge: Bridge,
f: impl FnOnce(A) -> R,
) -> Buffer<u8> {
// The initial `cached_buffer` contains the input.
Expand Down Expand Up @@ -418,7 +435,7 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
extern "C" fn run(
bridge: Bridge<'_>,
bridge: Bridge,
f: impl FnOnce(crate::TokenStream) -> crate::TokenStream,
) -> Buffer<u8> {
run_client(bridge, |input| f(crate::TokenStream(input)).0)
Expand All @@ -432,7 +449,7 @@ impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
) -> Self {
extern "C" fn run(
bridge: Bridge<'_>,
bridge: Bridge,
f: impl FnOnce(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
) -> Buffer<u8> {
run_client(bridge, |(input, input2)| {
Expand Down
28 changes: 0 additions & 28 deletions library/proc_macro/src/bridge/closure.rs

This file was deleted.

6 changes: 2 additions & 4 deletions library/proc_macro/src/bridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,6 @@ macro_rules! reverse_decode {
mod buffer;
#[forbid(unsafe_code)]
pub mod client;
#[allow(unsafe_code)]
mod closure;
#[forbid(unsafe_code)]
mod handle;
#[macro_use]
Expand All @@ -221,13 +219,13 @@ use rpc::{Decode, DecodeMut, Encode, Reader, Writer};
/// field of `client::Client`. The client holds its copy of the `Bridge`
/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`).
#[repr(C)]
pub struct Bridge<'a> {
pub struct Bridge {
/// Reusable buffer (only `clear`-ed, never shrunk), primarily
/// used for making requests, but also for passing input to client.
cached_buffer: Buffer<u8>,

/// Server-side function that the client uses to make requests.
dispatch: closure::Closure<'a, Buffer<u8>, Buffer<u8>>,
dispatch: extern "C" fn(Buffer<u8>) -> Buffer<u8>,

/// If 'true', always invoke the default panic hook
force_show_panics: bool,
Expand Down
5 changes: 3 additions & 2 deletions library/proc_macro/src/bridge/scoped_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ impl<T: LambdaL> ScopedCell<T> {

/// Sets the value in `self` to `replacement` while
/// running `f`, which gets the old value, mutably.
///
/// The old value will be restored after `f` exits, even
/// by panic, including modifications made to it by `f`.
pub fn replace<'a, R>(
pub fn replace_during<'a, R>(
&self,
replacement: <T as ApplyL<'a>>::Out,
f: impl for<'b, 'c> FnOnce(RefMutL<'b, 'c, T>) -> R,
Expand Down Expand Up @@ -76,6 +77,6 @@ impl<T: LambdaL> ScopedCell<T> {

/// Sets the value in `self` to `value` while running `f`.
pub fn set<R>(&self, value: <T as ApplyL<'_>>::Out, f: impl FnOnce() -> R) -> R {
self.replace(value, |_| f())
self.replace_during(value, |_| f())
}
}
17 changes: 10 additions & 7 deletions library/proc_macro/src/bridge/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ fn run_bridge_and_client<D: Copy + Send + 'static>(
strategy: &impl ExecutionStrategy,
server_thread_dispatch: impl FnMut(Buffer<u8>) -> Buffer<u8>,
input: Buffer<u8>,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
run_client: extern "C" fn(Bridge, D) -> Buffer<u8>,
client_data: D,
force_show_panics: bool,
) -> Buffer<u8> {
Expand All @@ -268,18 +268,21 @@ fn run_bridge_and_client<D: Copy + Send + 'static>(
strategy.cross_thread_dispatch(server_thread_dispatch, move |client_thread_dispatch| {
CLIENT_THREAD_DISPATCH.with(|dispatch_slot| {
dispatch_slot.set(Some(client_thread_dispatch), || {
let mut dispatch = |b| {
extern "C" fn dispatch(b: Buffer<u8>) -> Buffer<u8> {
CLIENT_THREAD_DISPATCH.with(|dispatch_slot| {
dispatch_slot.replace(None, |mut client_thread_dispatch| {
client_thread_dispatch.as_mut().unwrap()(b)
dispatch_slot.replace_during(None, |mut client_thread_dispatch| {
client_thread_dispatch.as_mut().expect(
"proc_macro::bridge::server: dispatch used on \
thread lacking an active server-side dispatcher",
)(b)
})
})
};
}

run_client(
Bridge {
cached_buffer: input,
dispatch: (&mut dispatch).into(),
dispatch,
force_show_panics,
_marker: marker::PhantomData,
},
Expand All @@ -300,7 +303,7 @@ fn run_server<
handle_counters: &'static client::HandleCounters,
server: S,
input: I,
run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>,
run_client: extern "C" fn(Bridge, D) -> Buffer<u8>,
client_data: D,
force_show_panics: bool,
) -> Result<O, PanicMessage> {
Expand Down

0 comments on commit 9242c12

Please sign in to comment.