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;
|
||||||
mod uri_parsing;
|
mod uri_parsing;
|
||||||
mod test_guide;
|
mod test_guide;
|
||||||
mod export;
|
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(
|
fn struct_maker_vec(
|
||||||
input: proc_macro::TokenStream,
|
input: proc_macro::TokenStream,
|
||||||
|
@ -70,3 +71,8 @@ pub fn export_internal(input: proc_macro::TokenStream) -> TokenStream {
|
||||||
export::_macro(input)
|
export::_macro(input)
|
||||||
.unwrap_or_else(|diag| diag.emit_as_item_tokens())
|
.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))
|
emit!(bang::uri_macro(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[proc_macro]
|
|
||||||
/// Internal macro: `rocket_internal_uri!`.
|
/// Internal macro: `rocket_internal_uri!`.
|
||||||
|
#[proc_macro]
|
||||||
|
#[doc(hidden)]
|
||||||
pub fn rocket_internal_uri(input: TokenStream) -> TokenStream {
|
pub fn rocket_internal_uri(input: TokenStream) -> TokenStream {
|
||||||
emit!(bang::uri_internal_macro(input))
|
emit!(bang::uri_internal_macro(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
/// Internal macro: `__typed_stream!`.
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn __typed_stream(input: TokenStream) -> TokenStream {
|
||||||
|
emit!(bang::typed_stream(input))
|
||||||
|
}
|
||||||
|
|
||||||
/// Private Rocket internal macro: `internal_guide_tests!`.
|
/// Private Rocket internal macro: `internal_guide_tests!`.
|
||||||
|
#[proc_macro]
|
||||||
|
#[doc(hidden)]
|
||||||
pub fn internal_guide_tests(input: TokenStream) -> TokenStream {
|
pub fn internal_guide_tests(input: TokenStream) -> TokenStream {
|
||||||
emit!(bang::guide_tests_internal(input))
|
emit!(bang::guide_tests_internal(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[proc_macro]
|
|
||||||
/// Private Rocket internal macro: `export!`.
|
/// Private Rocket internal macro: `export!`.
|
||||||
|
#[proc_macro]
|
||||||
|
#[doc(hidden)]
|
||||||
pub fn export(input: TokenStream) -> TokenStream {
|
pub fn export(input: TokenStream) -> TokenStream {
|
||||||
emit!(bang::export_internal(input))
|
emit!(bang::export_internal(input))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
use rocket::{Request, Rocket, Build};
|
use rocket::{Request, Rocket, Build};
|
||||||
use rocket::local::blocking::Client;
|
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_0() -> &'static str { "404-0" }
|
||||||
#[catch(404)] fn not_found_1(_: &Request) -> &'static str { "404-1" }
|
#[catch(404)] fn not_found_1(_: &Request) -> &'static str { "404-1" }
|
||||||
|
|
|
@ -78,7 +78,6 @@ crate::export! {
|
||||||
/// See [`struct@ByteStream`] and the [module level
|
/// See [`struct@ByteStream`] and the [module level
|
||||||
/// docs](crate::response::stream#typed-streams) for usage details.
|
/// docs](crate::response::stream#typed-streams) for usage details.
|
||||||
macro_rules! ByteStream {
|
macro_rules! ByteStream {
|
||||||
($T:ty) => ($crate::_typed_stream!(ByteStream, $T));
|
|
||||||
($($s:tt)*) => ($crate::_typed_stream!(ByteStream, $($s)*));
|
($($s:tt)*) => ($crate::_typed_stream!(ByteStream, $($s)*));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,10 +223,12 @@ crate::export! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _typed_stream {
|
macro_rules! _typed_stream {
|
||||||
($S:ident, $T:ty) => (
|
|
||||||
$crate::response::stream::$S<impl $crate::futures::stream::Stream<Item = $T>>
|
|
||||||
);
|
|
||||||
($S:ident, $($t:tt)*) => (
|
($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
|
/// See [`struct@ReaderStream`] and the [module level
|
||||||
/// docs](crate::response::stream#typed-streams) for usage details.
|
/// docs](crate::response::stream#typed-streams) for usage details.
|
||||||
macro_rules! ReaderStream {
|
macro_rules! ReaderStream {
|
||||||
($T:ty) => ($crate::_typed_stream!(ReaderStream, $T));
|
|
||||||
($($s:tt)*) => ($crate::_typed_stream!(ReaderStream, $($s)*));
|
($($s:tt)*) => ($crate::_typed_stream!(ReaderStream, $($s)*));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,6 @@ crate::export! {
|
||||||
/// See [`struct@TextStream`] and the [module level
|
/// See [`struct@TextStream`] and the [module level
|
||||||
/// docs](crate::response::stream#typed-streams) for usage details.
|
/// docs](crate::response::stream#typed-streams) for usage details.
|
||||||
macro_rules! TextStream {
|
macro_rules! TextStream {
|
||||||
($T:ty) => ($crate::_typed_stream!(TextStream, $T));
|
|
||||||
($($s:tt)*) => ($crate::_typed_stream!(TextStream, $($s)*));
|
($($s:tt)*) => ($crate::_typed_stream!(TextStream, $($s)*));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue