mirror of https://github.com/rwf2/Rocket.git
Add internal '__typed_stream' proc-macro.
This resolves syntax ambiguity issues with public typed-stream macros. Prior to this commit, greedy single-token matching by macro-rules macros would result in certain tokens at the beginning of the macro input, such as 'for', inadvertently triggering a '$ty' matching case resulting in incorrect expansion.
This commit is contained in:
parent
009be32a8c
commit
ed3cc13b84
|
@ -1,12 +1,13 @@
|
|||
use devise::Result;
|
||||
use syn::{Path, punctuated::Punctuated, parse::Parser, Token};
|
||||
use syn::spanned::Spanned;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
mod uri;
|
||||
mod uri_parsing;
|
||||
mod test_guide;
|
||||
mod export;
|
||||
mod typed_stream;
|
||||
|
||||
use devise::Result;
|
||||
use syn::{Path, punctuated::Punctuated, parse::Parser, Token};
|
||||
use syn::spanned::Spanned;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
fn struct_maker_vec(
|
||||
input: proc_macro::TokenStream,
|
||||
|
@ -70,3 +71,8 @@ pub fn export_internal(input: proc_macro::TokenStream) -> TokenStream {
|
|||
export::_macro(input)
|
||||
.unwrap_or_else(|diag| diag.emit_as_item_tokens())
|
||||
}
|
||||
|
||||
pub fn typed_stream(input: proc_macro::TokenStream) -> TokenStream {
|
||||
typed_stream::_macro(input)
|
||||
.unwrap_or_else(|diag| diag.emit_as_item_tokens())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use syn::parse::{Parse, ParseStream, discouraged::Speculative};
|
||||
|
||||
enum Input {
|
||||
Type(syn::Type),
|
||||
Tokens(TokenStream)
|
||||
}
|
||||
|
||||
struct Invocation {
|
||||
ty_stream_ty: syn::Path,
|
||||
stream_mac: syn::Path,
|
||||
stream_trait: syn::Path,
|
||||
input: Input,
|
||||
}
|
||||
|
||||
impl Parse for Invocation {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
let ty_stream_ty = input.parse()?;
|
||||
input.parse::<syn::Token![,]>()?;
|
||||
|
||||
let stream_mac = input.parse()?;
|
||||
input.parse::<syn::Token![,]>()?;
|
||||
|
||||
let stream_trait = input.parse()?;
|
||||
input.parse::<syn::Token![,]>()?;
|
||||
|
||||
let fork = input.fork();
|
||||
let input = match fork.parse() {
|
||||
Ok(ty) => {
|
||||
input.advance_to(&fork);
|
||||
Input::Type(ty)
|
||||
}
|
||||
Err(_) => Input::Tokens(input.parse()?)
|
||||
};
|
||||
|
||||
Ok(Invocation { ty_stream_ty, stream_mac, stream_trait, input })
|
||||
}
|
||||
}
|
||||
|
||||
/// This macro exists because we want to disambiguate between input of a type
|
||||
/// and input of an expression that looks like a type. `macro_rules` matches
|
||||
/// eagerly on a single token, so something like `foo!(for x in 0..10 {})` will
|
||||
/// match a `($ty)` branch as will anything that starts with a path.
|
||||
pub fn _macro(input: proc_macro::TokenStream) -> devise::Result<TokenStream> {
|
||||
let i: Invocation = syn::parse(input)?;
|
||||
let (s_ty, mac, s_trait) = (i.ty_stream_ty, i.stream_mac, i.stream_trait);
|
||||
let tokens = match i.input {
|
||||
Input::Tokens(tt) => quote!(#s_ty::from(#mac!(#tt))),
|
||||
Input::Type(ty) => quote!(#s_ty<impl #s_trait<Item = #ty>>),
|
||||
};
|
||||
|
||||
Ok(tokens)
|
||||
}
|
|
@ -1345,23 +1345,30 @@ pub fn uri(input: TokenStream) -> TokenStream {
|
|||
emit!(bang::uri_macro(input))
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[proc_macro]
|
||||
/// Internal macro: `rocket_internal_uri!`.
|
||||
#[proc_macro]
|
||||
#[doc(hidden)]
|
||||
pub fn rocket_internal_uri(input: TokenStream) -> TokenStream {
|
||||
emit!(bang::uri_internal_macro(input))
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Internal macro: `__typed_stream!`.
|
||||
#[proc_macro]
|
||||
#[doc(hidden)]
|
||||
pub fn __typed_stream(input: TokenStream) -> TokenStream {
|
||||
emit!(bang::typed_stream(input))
|
||||
}
|
||||
|
||||
/// Private Rocket internal macro: `internal_guide_tests!`.
|
||||
#[proc_macro]
|
||||
#[doc(hidden)]
|
||||
pub fn internal_guide_tests(input: TokenStream) -> TokenStream {
|
||||
emit!(bang::guide_tests_internal(input))
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[proc_macro]
|
||||
/// Private Rocket internal macro: `export!`.
|
||||
#[proc_macro]
|
||||
#[doc(hidden)]
|
||||
pub fn export(input: TokenStream) -> TokenStream {
|
||||
emit!(bang::export_internal(input))
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
use rocket::{Request, Rocket, Build};
|
||||
use rocket::local::blocking::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
use rocket::http::Status;
|
||||
|
||||
#[catch(404)] fn not_found_0() -> &'static str { "404-0" }
|
||||
#[catch(404)] fn not_found_1(_: &Request) -> &'static str { "404-1" }
|
||||
|
|
|
@ -78,7 +78,6 @@ crate::export! {
|
|||
/// See [`struct@ByteStream`] and the [module level
|
||||
/// docs](crate::response::stream#typed-streams) for usage details.
|
||||
macro_rules! ByteStream {
|
||||
($T:ty) => ($crate::_typed_stream!(ByteStream, $T));
|
||||
($($s:tt)*) => ($crate::_typed_stream!(ByteStream, $($s)*));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,10 +223,12 @@ crate::export! {
|
|||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! _typed_stream {
|
||||
($S:ident, $T:ty) => (
|
||||
$crate::response::stream::$S<impl $crate::futures::stream::Stream<Item = $T>>
|
||||
);
|
||||
($S:ident, $($t:tt)*) => (
|
||||
$crate::response::stream::$S::from($crate::response::stream::stream!($($t)*))
|
||||
);
|
||||
$crate::__typed_stream! {
|
||||
$crate::response::stream::$S,
|
||||
$crate::response::stream::stream,
|
||||
$crate::futures::stream::Stream,
|
||||
$($t)*
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -199,7 +199,6 @@ crate::export! {
|
|||
/// See [`struct@ReaderStream`] and the [module level
|
||||
/// docs](crate::response::stream#typed-streams) for usage details.
|
||||
macro_rules! ReaderStream {
|
||||
($T:ty) => ($crate::_typed_stream!(ReaderStream, $T));
|
||||
($($s:tt)*) => ($crate::_typed_stream!(ReaderStream, $($s)*));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,6 @@ crate::export! {
|
|||
/// See [`struct@TextStream`] and the [module level
|
||||
/// docs](crate::response::stream#typed-streams) for usage details.
|
||||
macro_rules! TextStream {
|
||||
($T:ty) => ($crate::_typed_stream!(TextStream, $T));
|
||||
($($s:tt)*) => ($crate::_typed_stream!(TextStream, $($s)*));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue