Rollup merge of #152166 - cyrgani:questionable-pm-cleanups, r=petrochenkov
cleanup some more things in `proc_macro::bridge` Each commit should be reviewable on its own.
This commit is contained in:
commit
e2ddf5c951
7 changed files with 122 additions and 153 deletions
|
|
@ -121,7 +121,7 @@ macro_rules! define_client_side {
|
|||
}
|
||||
}
|
||||
}
|
||||
with_api!(self, define_client_side);
|
||||
with_api!(define_client_side, TokenStream, Span, Symbol);
|
||||
|
||||
struct Bridge<'a> {
|
||||
/// Reusable buffer (only `clear`-ed, never shrunk), primarily
|
||||
|
|
@ -129,7 +129,7 @@ struct Bridge<'a> {
|
|||
cached_buffer: Buffer,
|
||||
|
||||
/// Server-side function that the client uses to make requests.
|
||||
dispatch: closure::Closure<'a, Buffer, Buffer>,
|
||||
dispatch: closure::Closure<'a>,
|
||||
|
||||
/// Provided globals for this macro expansion.
|
||||
globals: ExpnGlobals<Span>,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
//! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`.
|
||||
//! Closure type (equivalent to `&mut dyn FnMut(Buffer) -> Buffer`) that's `repr(C)`.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::Buffer;
|
||||
|
||||
#[repr(C)]
|
||||
pub(super) struct Closure<'a, A, R> {
|
||||
call: unsafe extern "C" fn(*mut Env, A) -> R,
|
||||
pub(super) struct Closure<'a> {
|
||||
call: extern "C" fn(*mut Env, Buffer) -> Buffer,
|
||||
env: *mut Env,
|
||||
// Prevent Send and Sync impls.
|
||||
//
|
||||
|
|
@ -14,17 +16,17 @@ pub(super) struct Closure<'a, A, R> {
|
|||
|
||||
struct Env;
|
||||
|
||||
impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> {
|
||||
impl<'a, F: FnMut(Buffer) -> Buffer> From<&'a mut F> for Closure<'a> {
|
||||
fn from(f: &'a mut F) -> Self {
|
||||
unsafe extern "C" fn call<A, R, F: FnMut(A) -> R>(env: *mut Env, arg: A) -> R {
|
||||
extern "C" fn call<F: FnMut(Buffer) -> Buffer>(env: *mut Env, arg: Buffer) -> Buffer {
|
||||
unsafe { (*(env as *mut _ as *mut F))(arg) }
|
||||
}
|
||||
Closure { call: call::<A, R, F>, env: f as *mut _ as *mut Env, _marker: PhantomData }
|
||||
Closure { call: call::<F>, env: f as *mut _ as *mut Env, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A, R> Closure<'a, A, R> {
|
||||
pub(super) fn call(&mut self, arg: A) -> R {
|
||||
unsafe { (self.call)(self.env, arg) }
|
||||
impl<'a> Closure<'a> {
|
||||
pub(super) fn call(&mut self, arg: Buffer) -> Buffer {
|
||||
(self.call)(self.env, arg)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,71 +18,67 @@ use crate::{Delimiter, Level};
|
|||
/// Higher-order macro describing the server RPC API, allowing automatic
|
||||
/// generation of type-safe Rust APIs, both client-side and server-side.
|
||||
///
|
||||
/// `with_api!(MySelf, my_macro)` expands to:
|
||||
/// `with_api!(my_macro, MyTokenStream, MySpan, MySymbol)` expands to:
|
||||
/// ```rust,ignore (pseudo-code)
|
||||
/// my_macro! {
|
||||
/// fn lit_character(ch: char) -> MySelf::Literal;
|
||||
/// fn lit_span(lit: &MySelf::Literal) -> MySelf::Span;
|
||||
/// fn lit_set_span(lit: &mut MySelf::Literal, span: MySelf::Span);
|
||||
/// fn ts_clone(stream: &MyTokenStream) -> MyTokenStream;
|
||||
/// fn span_debug(span: &MySpan) -> String;
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The first argument serves to customize the argument/return types,
|
||||
/// to enable several different usecases:
|
||||
///
|
||||
/// If `MySelf` is just `Self`, then the types are only valid inside
|
||||
/// a trait or a trait impl, where the trait has associated types
|
||||
/// for each of the API types. If non-associated types are desired,
|
||||
/// a module name (`self` in practice) can be used instead of `Self`.
|
||||
/// The second (`TokenStream`), third (`Span`) and fourth (`Symbol`)
|
||||
/// argument serve to customize the argument/return types that need
|
||||
/// special handling, to enable several different representations of
|
||||
/// these types.
|
||||
macro_rules! with_api {
|
||||
($S:ident, $m:ident) => {
|
||||
($m:ident, $TokenStream: path, $Span: path, $Symbol: path) => {
|
||||
$m! {
|
||||
fn injected_env_var(var: &str) -> Option<String>;
|
||||
fn track_env_var(var: &str, value: Option<&str>);
|
||||
fn track_path(path: &str);
|
||||
fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>;
|
||||
fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>);
|
||||
fn literal_from_str(s: &str) -> Result<Literal<$Span, $Symbol>, ()>;
|
||||
fn emit_diagnostic(diagnostic: Diagnostic<$Span>);
|
||||
|
||||
fn ts_drop(stream: $S::TokenStream);
|
||||
fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream;
|
||||
fn ts_is_empty(stream: &$S::TokenStream) -> bool;
|
||||
fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
|
||||
fn ts_from_str(src: &str) -> $S::TokenStream;
|
||||
fn ts_to_string(stream: &$S::TokenStream) -> String;
|
||||
fn ts_drop(stream: $TokenStream);
|
||||
fn ts_clone(stream: &$TokenStream) -> $TokenStream;
|
||||
fn ts_is_empty(stream: &$TokenStream) -> bool;
|
||||
fn ts_expand_expr(stream: &$TokenStream) -> Result<$TokenStream, ()>;
|
||||
fn ts_from_str(src: &str) -> $TokenStream;
|
||||
fn ts_to_string(stream: &$TokenStream) -> String;
|
||||
fn ts_from_token_tree(
|
||||
tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>,
|
||||
) -> $S::TokenStream;
|
||||
tree: TokenTree<$TokenStream, $Span, $Symbol>,
|
||||
) -> $TokenStream;
|
||||
fn ts_concat_trees(
|
||||
base: Option<$S::TokenStream>,
|
||||
trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>,
|
||||
) -> $S::TokenStream;
|
||||
base: Option<$TokenStream>,
|
||||
trees: Vec<TokenTree<$TokenStream, $Span, $Symbol>>,
|
||||
) -> $TokenStream;
|
||||
fn ts_concat_streams(
|
||||
base: Option<$S::TokenStream>,
|
||||
streams: Vec<$S::TokenStream>,
|
||||
) -> $S::TokenStream;
|
||||
base: Option<$TokenStream>,
|
||||
streams: Vec<$TokenStream>,
|
||||
) -> $TokenStream;
|
||||
fn ts_into_trees(
|
||||
stream: $S::TokenStream
|
||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
||||
stream: $TokenStream
|
||||
) -> Vec<TokenTree<$TokenStream, $Span, $Symbol>>;
|
||||
|
||||
fn span_debug(span: $S::Span) -> String;
|
||||
fn span_parent(span: $S::Span) -> Option<$S::Span>;
|
||||
fn span_source(span: $S::Span) -> $S::Span;
|
||||
fn span_byte_range(span: $S::Span) -> Range<usize>;
|
||||
fn span_start(span: $S::Span) -> $S::Span;
|
||||
fn span_end(span: $S::Span) -> $S::Span;
|
||||
fn span_line(span: $S::Span) -> usize;
|
||||
fn span_column(span: $S::Span) -> usize;
|
||||
fn span_file(span: $S::Span) -> String;
|
||||
fn span_local_file(span: $S::Span) -> Option<String>;
|
||||
fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||
fn span_subspan(span: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||
fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span;
|
||||
fn span_source_text(span: $S::Span) -> Option<String>;
|
||||
fn span_save_span(span: $S::Span) -> usize;
|
||||
fn span_recover_proc_macro_span(id: usize) -> $S::Span;
|
||||
fn span_debug(span: $Span) -> String;
|
||||
fn span_parent(span: $Span) -> Option<$Span>;
|
||||
fn span_source(span: $Span) -> $Span;
|
||||
fn span_byte_range(span: $Span) -> Range<usize>;
|
||||
fn span_start(span: $Span) -> $Span;
|
||||
fn span_end(span: $Span) -> $Span;
|
||||
fn span_line(span: $Span) -> usize;
|
||||
fn span_column(span: $Span) -> usize;
|
||||
fn span_file(span: $Span) -> String;
|
||||
fn span_local_file(span: $Span) -> Option<String>;
|
||||
fn span_join(span: $Span, other: $Span) -> Option<$Span>;
|
||||
fn span_subspan(span: $Span, start: Bound<usize>, end: Bound<usize>) -> Option<$Span>;
|
||||
fn span_resolved_at(span: $Span, at: $Span) -> $Span;
|
||||
fn span_source_text(span: $Span) -> Option<String>;
|
||||
fn span_save_span(span: $Span) -> usize;
|
||||
fn span_recover_proc_macro_span(id: usize) -> $Span;
|
||||
|
||||
fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>;
|
||||
fn symbol_normalize_and_validate_ident(string: &str) -> Result<$Symbol, ()>;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -126,7 +122,7 @@ pub struct BridgeConfig<'a> {
|
|||
input: Buffer,
|
||||
|
||||
/// Server-side function that the client uses to make requests.
|
||||
dispatch: closure::Closure<'a, Buffer, Buffer>,
|
||||
dispatch: closure::Closure<'a>,
|
||||
|
||||
/// If 'true', always invoke the default panic hook
|
||||
force_show_panics: bool,
|
||||
|
|
@ -146,7 +142,7 @@ macro_rules! declare_tags {
|
|||
rpc_encode_decode!(enum ApiTags { $($method),* });
|
||||
}
|
||||
}
|
||||
with_api!(self, declare_tags);
|
||||
with_api!(declare_tags, __, __, __);
|
||||
|
||||
/// Helper to wrap associated types to allow trait impl dispatch.
|
||||
/// That is, normally a pair of impls for `T::Foo` and `T::Bar`
|
||||
|
|
@ -173,7 +169,7 @@ impl<T, M> Mark for Marked<T, M> {
|
|||
self.value
|
||||
}
|
||||
}
|
||||
impl<'a, T, M> Mark for &'a Marked<T, M> {
|
||||
impl<'a, T> Mark for &'a Marked<T, client::TokenStream> {
|
||||
type Unmarked = &'a T;
|
||||
fn mark(_: Self::Unmarked) -> Self {
|
||||
unreachable!()
|
||||
|
|
@ -220,6 +216,8 @@ mark_noop! {
|
|||
Delimiter,
|
||||
LitKind,
|
||||
Level,
|
||||
Bound<usize>,
|
||||
Range<usize>,
|
||||
}
|
||||
|
||||
rpc_encode_decode!(
|
||||
|
|
@ -318,7 +316,7 @@ macro_rules! compound_traits {
|
|||
};
|
||||
}
|
||||
|
||||
compound_traits!(
|
||||
rpc_encode_decode!(
|
||||
enum Bound<T> {
|
||||
Included(x),
|
||||
Excluded(x),
|
||||
|
|
@ -390,7 +388,7 @@ pub struct Literal<Span, Symbol> {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
compound_traits!(struct Literal<Sp, Sy> { kind, symbol, suffix, span });
|
||||
compound_traits!(struct Literal<Span, Symbol> { kind, symbol, suffix, span });
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum TokenTree<TokenStream, Span, Symbol> {
|
||||
|
|
@ -434,6 +432,6 @@ compound_traits!(
|
|||
struct ExpnGlobals<Span> { def_site, call_site, mixed_site }
|
||||
);
|
||||
|
||||
compound_traits!(
|
||||
rpc_encode_decode!(
|
||||
struct Range<T> { start, end }
|
||||
);
|
||||
|
|
|
|||
|
|
@ -52,45 +52,37 @@ macro_rules! rpc_encode_decode {
|
|||
}
|
||||
};
|
||||
(enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => {
|
||||
impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
// HACK(eddyb): `Tag` enum duplicated between the
|
||||
// two impls as there's no other place to stash it.
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(u8)]
|
||||
enum Tag { $($variant),* }
|
||||
#[allow(non_upper_case_globals, non_camel_case_types)]
|
||||
const _: () = {
|
||||
#[repr(u8)] enum Tag { $($variant),* }
|
||||
|
||||
match self {
|
||||
$($name::$variant $(($field))* => {
|
||||
(Tag::$variant as u8).encode(w, s);
|
||||
$($field.encode(w, s);)*
|
||||
})*
|
||||
$(const $variant: u8 = Tag::$variant as u8;)*
|
||||
|
||||
impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
match self {
|
||||
$($name::$variant $(($field))* => {
|
||||
$variant.encode(w, s);
|
||||
$($field.encode(w, s);)*
|
||||
})*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S>
|
||||
for $name $(<$($T),+>)?
|
||||
{
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
// HACK(eddyb): `Tag` enum duplicated between the
|
||||
// two impls as there's no other place to stash it.
|
||||
#[allow(non_upper_case_globals, non_camel_case_types)]
|
||||
mod tag {
|
||||
#[repr(u8)] enum Tag { $($variant),* }
|
||||
|
||||
$(pub(crate) const $variant: u8 = Tag::$variant as u8;)*
|
||||
}
|
||||
|
||||
match u8::decode(r, s) {
|
||||
$(tag::$variant => {
|
||||
$(let $field = Decode::decode(r, s);)*
|
||||
$name::$variant $(($field))*
|
||||
})*
|
||||
_ => unreachable!(),
|
||||
impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S>
|
||||
for $name $(<$($T),+>)?
|
||||
{
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
match u8::decode(r, s) {
|
||||
$($variant => {
|
||||
$(let $field = Decode::decode(r, s);)*
|
||||
$name::$variant $(($field))*
|
||||
})*
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,47 +38,27 @@
|
|||
|
||||
use std::mem;
|
||||
|
||||
// FIXME(eddyb) this could be `trait` impls except for the `const fn` requirement.
|
||||
macro_rules! define_reify_functions {
|
||||
($(
|
||||
fn $name:ident $(<$($param:ident),*>)?
|
||||
for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty;
|
||||
)+) => {
|
||||
$(pub(super) const fn $name<
|
||||
$($($param,)*)?
|
||||
F: Fn($($arg_ty),*) -> $ret_ty + Copy
|
||||
>(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty {
|
||||
// FIXME(eddyb) describe the `F` type (e.g. via `type_name::<F>`) once panic
|
||||
// formatting becomes possible in `const fn`.
|
||||
const { assert!(size_of::<F>() == 0, "selfless_reify: closure must be zero-sized"); }
|
||||
|
||||
$(extern $abi)? fn wrapper<
|
||||
$($($param,)*)?
|
||||
F: Fn($($arg_ty),*) -> $ret_ty + Copy
|
||||
>($($arg: $arg_ty),*) -> $ret_ty {
|
||||
let f = unsafe {
|
||||
// SAFETY: `F` satisfies all criteria for "out of thin air"
|
||||
// reconstructability (see module-level doc comment).
|
||||
mem::MaybeUninit::<F>::uninit().assume_init()
|
||||
};
|
||||
f($($arg),*)
|
||||
}
|
||||
let _f_proof = f;
|
||||
wrapper::<
|
||||
$($($param,)*)?
|
||||
F
|
||||
>
|
||||
})+
|
||||
pub(super) const fn reify_to_extern_c_fn_hrt_bridge<
|
||||
R,
|
||||
F: Fn(super::BridgeConfig<'_>) -> R + Copy,
|
||||
>(
|
||||
f: F,
|
||||
) -> extern "C" fn(super::BridgeConfig<'_>) -> R {
|
||||
// FIXME(eddyb) describe the `F` type (e.g. via `type_name::<F>`) once panic
|
||||
// formatting becomes possible in `const fn`.
|
||||
const {
|
||||
assert!(size_of::<F>() == 0, "selfless_reify: closure must be zero-sized");
|
||||
}
|
||||
}
|
||||
|
||||
define_reify_functions! {
|
||||
fn _reify_to_extern_c_fn_unary<A, R> for extern "C" fn(arg: A) -> R;
|
||||
|
||||
// HACK(eddyb) this abstraction is used with `for<'a> fn(BridgeConfig<'a>)
|
||||
// -> T` but that doesn't work with just `reify_to_extern_c_fn_unary`
|
||||
// because of the `fn` pointer type being "higher-ranked" (i.e. the
|
||||
// `for<'a>` binder).
|
||||
// FIXME(eddyb) try to remove the lifetime from `BridgeConfig`, that'd help.
|
||||
fn reify_to_extern_c_fn_hrt_bridge<R> for extern "C" fn(bridge: super::BridgeConfig<'_>) -> R;
|
||||
extern "C" fn wrapper<R, F: Fn(super::BridgeConfig<'_>) -> R + Copy>(
|
||||
bridge: super::BridgeConfig<'_>,
|
||||
) -> R {
|
||||
let f = unsafe {
|
||||
// SAFETY: `F` satisfies all criteria for "out of thin air"
|
||||
// reconstructability (see module-level doc comment).
|
||||
mem::conjure_zst::<F>()
|
||||
};
|
||||
f(bridge)
|
||||
}
|
||||
let _f_proof = f;
|
||||
wrapper::<R, F>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,12 +58,12 @@ struct Dispatcher<S: Server> {
|
|||
server: S,
|
||||
}
|
||||
|
||||
macro_rules! define_server_dispatcher_impl {
|
||||
macro_rules! define_server {
|
||||
(
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
) => {
|
||||
pub trait Server {
|
||||
type TokenStream: 'static + Clone;
|
||||
type TokenStream: 'static + Clone + Default;
|
||||
type Span: 'static + Copy + Eq + Hash;
|
||||
type Symbol: 'static;
|
||||
|
||||
|
|
@ -77,22 +77,20 @@ macro_rules! define_server_dispatcher_impl {
|
|||
|
||||
$(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?;)*
|
||||
}
|
||||
}
|
||||
}
|
||||
with_api!(define_server, Self::TokenStream, Self::Span, Self::Symbol);
|
||||
|
||||
macro_rules! define_dispatcher {
|
||||
(
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
) => {
|
||||
// FIXME(eddyb) `pub` only for `ExecutionStrategy` below.
|
||||
pub trait DispatcherTrait {
|
||||
// HACK(eddyb) these are here to allow `Self::$name` to work below.
|
||||
type TokenStream;
|
||||
type Span;
|
||||
type Symbol;
|
||||
|
||||
fn dispatch(&mut self, buf: Buffer) -> Buffer;
|
||||
}
|
||||
|
||||
impl<S: Server> DispatcherTrait for Dispatcher<S> {
|
||||
type TokenStream = MarkedTokenStream<S>;
|
||||
type Span = MarkedSpan<S>;
|
||||
type Symbol = MarkedSymbol<S>;
|
||||
|
||||
fn dispatch(&mut self, mut buf: Buffer) -> Buffer {
|
||||
let Dispatcher { handle_store, server } = self;
|
||||
|
||||
|
|
@ -127,7 +125,7 @@ macro_rules! define_server_dispatcher_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
with_api!(Self, define_server_dispatcher_impl);
|
||||
with_api!(define_dispatcher, MarkedTokenStream<S>, MarkedSpan<S>, MarkedSymbol<S>);
|
||||
|
||||
pub trait ExecutionStrategy {
|
||||
fn run_bridge_and_client(
|
||||
|
|
@ -312,7 +310,6 @@ impl client::Client<crate::TokenStream, crate::TokenStream> {
|
|||
) -> Result<S::TokenStream, PanicMessage>
|
||||
where
|
||||
S: Server,
|
||||
S::TokenStream: Default,
|
||||
{
|
||||
let client::Client { handle_counters, run, _marker } = *self;
|
||||
run_server(
|
||||
|
|
@ -338,7 +335,6 @@ impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream
|
|||
) -> Result<S::TokenStream, PanicMessage>
|
||||
where
|
||||
S: Server,
|
||||
S::TokenStream: Default,
|
||||
{
|
||||
let client::Client { handle_counters, run, _marker } = *self;
|
||||
run_server(
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#![feature(restricted_std)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(mem_conjure_zst)]
|
||||
#![recursion_limit = "256"]
|
||||
#![allow(internal_features)]
|
||||
#![deny(ffi_unwind_calls)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue