mirror of https://github.com/fafhrd91/actix-web
unify #route and #get, #post ...
This commit is contained in:
parent
f7bcad9567
commit
561d7b8bf0
|
@ -58,7 +58,7 @@ use proc_macro::TokenStream;
|
||||||
/// - `wrap = "Middleware"` - Registers a resource middleware.
|
/// - `wrap = "Middleware"` - Registers a resource middleware.
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn get(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn get(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Get)
|
route::with_method(Some(route::Method::Get), args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates route handler with `POST` method guard.
|
/// Creates route handler with `POST` method guard.
|
||||||
|
@ -68,7 +68,7 @@ pub fn get(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// Attributes are the same as in [get](attr.get.html)
|
/// Attributes are the same as in [get](attr.get.html)
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn post(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn post(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Post)
|
route::with_method(Some(route::Method::Post), args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates route handler with `PUT` method guard.
|
/// Creates route handler with `PUT` method guard.
|
||||||
|
@ -78,7 +78,7 @@ pub fn post(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// Attributes are the same as in [get](attr.get.html)
|
/// Attributes are the same as in [get](attr.get.html)
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn put(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn put(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Put)
|
route::with_method(Some(route::Method::Put), args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates route handler with `DELETE` method guard.
|
/// Creates route handler with `DELETE` method guard.
|
||||||
|
@ -88,7 +88,7 @@ pub fn put(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// Attributes are the same as in [get](attr.get.html).
|
/// Attributes are the same as in [get](attr.get.html).
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Delete)
|
route::with_method(Some(route::Method::Delete), args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates route handler with `HEAD` method guard.
|
/// Creates route handler with `HEAD` method guard.
|
||||||
|
@ -98,7 +98,7 @@ pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// Attributes are the same as in [get](attr.get.html).
|
/// Attributes are the same as in [get](attr.get.html).
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn head(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn head(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Head)
|
route::with_method(Some(route::Method::Head), args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates route handler with `CONNECT` method guard.
|
/// Creates route handler with `CONNECT` method guard.
|
||||||
|
@ -108,7 +108,7 @@ pub fn head(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// Attributes are the same as in [get](attr.get.html).
|
/// Attributes are the same as in [get](attr.get.html).
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Connect)
|
route::with_method(Some(route::Method::Connect), args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates route handler with `OPTIONS` method guard.
|
/// Creates route handler with `OPTIONS` method guard.
|
||||||
|
@ -118,7 +118,7 @@ pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// Attributes are the same as in [get](attr.get.html).
|
/// Attributes are the same as in [get](attr.get.html).
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn options(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn options(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Options)
|
route::with_method(Some(route::Method::Options), args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates route handler with `TRACE` method guard.
|
/// Creates route handler with `TRACE` method guard.
|
||||||
|
@ -128,7 +128,7 @@ pub fn options(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// Attributes are the same as in [get](attr.get.html).
|
/// Attributes are the same as in [get](attr.get.html).
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Trace)
|
route::with_method(Some(route::Method::Trace), args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates route handler with `PATCH` method guard.
|
/// Creates route handler with `PATCH` method guard.
|
||||||
|
@ -138,7 +138,7 @@ pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// Attributes are the same as in [get](attr.get.html).
|
/// Attributes are the same as in [get](attr.get.html).
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn patch(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn patch(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Patch)
|
route::with_method(Some(route::Method::Patch), args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates resource handler, allowing multiple HTTP method guards.
|
/// Creates resource handler, allowing multiple HTTP method guards.
|
||||||
|
@ -155,7 +155,7 @@ pub fn patch(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// - `wrap="Middleware"` - Registers a resource middleware.
|
/// - `wrap="Middleware"` - Registers a resource middleware.
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn route(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn route(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
route::generate(args, input, route::GuardType::Multi)
|
route::with_method(None, args, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks async main function as the actix system entry-point.
|
/// Marks async main function as the actix system entry-point.
|
||||||
|
|
|
@ -21,7 +21,7 @@ impl ToTokens for ResourceType {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum GuardType {
|
pub enum Method {
|
||||||
Get,
|
Get,
|
||||||
Post,
|
Post,
|
||||||
Put,
|
Put,
|
||||||
|
@ -31,47 +31,45 @@ pub enum GuardType {
|
||||||
Options,
|
Options,
|
||||||
Trace,
|
Trace,
|
||||||
Patch,
|
Patch,
|
||||||
Multi,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GuardType {
|
impl Method {
|
||||||
fn as_str(&self) -> &'static str {
|
fn as_str(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
GuardType::Get => "Get",
|
Method::Get => "Get",
|
||||||
GuardType::Post => "Post",
|
Method::Post => "Post",
|
||||||
GuardType::Put => "Put",
|
Method::Put => "Put",
|
||||||
GuardType::Delete => "Delete",
|
Method::Delete => "Delete",
|
||||||
GuardType::Head => "Head",
|
Method::Head => "Head",
|
||||||
GuardType::Connect => "Connect",
|
Method::Connect => "Connect",
|
||||||
GuardType::Options => "Options",
|
Method::Options => "Options",
|
||||||
GuardType::Trace => "Trace",
|
Method::Trace => "Trace",
|
||||||
GuardType::Patch => "Patch",
|
Method::Patch => "Patch",
|
||||||
GuardType::Multi => "Multi",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokens for GuardType {
|
impl ToTokens for Method {
|
||||||
fn to_tokens(&self, stream: &mut TokenStream2) {
|
fn to_tokens(&self, stream: &mut TokenStream2) {
|
||||||
let ident = Ident::new(self.as_str(), Span::call_site());
|
let ident = Ident::new(self.as_str(), Span::call_site());
|
||||||
stream.append(ident);
|
stream.append(ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&syn::LitStr> for GuardType {
|
impl TryFrom<&syn::LitStr> for Method {
|
||||||
type Error = syn::Error;
|
type Error = syn::Error;
|
||||||
|
|
||||||
fn try_from(value: &syn::LitStr) -> Result<Self, Self::Error> {
|
fn try_from(value: &syn::LitStr) -> Result<Self, Self::Error> {
|
||||||
match value.value().as_str() {
|
match value.value().as_str() {
|
||||||
"CONNECT" => Ok(GuardType::Connect),
|
"CONNECT" => Ok(Method::Connect),
|
||||||
"DELETE" => Ok(GuardType::Delete),
|
"DELETE" => Ok(Method::Delete),
|
||||||
"GET" => Ok(GuardType::Get),
|
"GET" => Ok(Method::Get),
|
||||||
"HEAD" => Ok(GuardType::Head),
|
"HEAD" => Ok(Method::Head),
|
||||||
"OPTIONS" => Ok(GuardType::Options),
|
"OPTIONS" => Ok(Method::Options),
|
||||||
"PATCH" => Ok(GuardType::Patch),
|
"PATCH" => Ok(Method::Patch),
|
||||||
"POST" => Ok(GuardType::Post),
|
"POST" => Ok(Method::Post),
|
||||||
"PUT" => Ok(GuardType::Put),
|
"PUT" => Ok(Method::Put),
|
||||||
"TRACE" => Ok(GuardType::Trace),
|
"TRACE" => Ok(Method::Trace),
|
||||||
_ => Err(syn::Error::new_spanned(
|
_ => Err(syn::Error::new_spanned(
|
||||||
value,
|
value,
|
||||||
&format!("Unexpected HTTP Method: `{}`", value.value()),
|
&format!("Unexpected HTTP Method: `{}`", value.value()),
|
||||||
|
@ -84,15 +82,14 @@ struct Args {
|
||||||
path: syn::LitStr,
|
path: syn::LitStr,
|
||||||
guards: Vec<Ident>,
|
guards: Vec<Ident>,
|
||||||
wrappers: Vec<syn::Type>,
|
wrappers: Vec<syn::Type>,
|
||||||
methods: HashSet<GuardType>,
|
methods: HashSet<Method>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
fn new(args: AttributeArgs) -> syn::Result<Self> {
|
fn new(args: AttributeArgs, mut methods: HashSet<Method>) -> syn::Result<Self> {
|
||||||
let mut path = None;
|
let mut path = None;
|
||||||
let mut guards = Vec::new();
|
let mut guards = Vec::new();
|
||||||
let mut wrappers = Vec::new();
|
let mut wrappers = Vec::new();
|
||||||
let mut methods = HashSet::new();
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
match arg {
|
match arg {
|
||||||
NestedMeta::Lit(syn::Lit::Str(lit)) => match path {
|
NestedMeta::Lit(syn::Lit::Str(lit)) => match path {
|
||||||
|
@ -127,8 +124,8 @@ impl Args {
|
||||||
}
|
}
|
||||||
} else if nv.path.is_ident("method") {
|
} else if nv.path.is_ident("method") {
|
||||||
if let syn::Lit::Str(ref lit) = nv.lit {
|
if let syn::Lit::Str(ref lit) = nv.lit {
|
||||||
let guard = GuardType::try_from(lit)?;
|
let method = Method::try_from(lit)?;
|
||||||
if !methods.insert(guard) {
|
if !methods.insert(method) {
|
||||||
return Err(syn::Error::new_spanned(
|
return Err(syn::Error::new_spanned(
|
||||||
&nv.lit,
|
&nv.lit,
|
||||||
&format!(
|
&format!(
|
||||||
|
@ -169,7 +166,6 @@ pub struct Route {
|
||||||
args: Args,
|
args: Args,
|
||||||
ast: syn::ItemFn,
|
ast: syn::ItemFn,
|
||||||
resource_type: ResourceType,
|
resource_type: ResourceType,
|
||||||
guard: GuardType,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guess_resource_type(typ: &syn::Type) -> ResourceType {
|
fn guess_resource_type(typ: &syn::Type) -> ResourceType {
|
||||||
|
@ -198,23 +194,26 @@ impl Route {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
args: AttributeArgs,
|
args: AttributeArgs,
|
||||||
input: TokenStream,
|
input: TokenStream,
|
||||||
guard: GuardType,
|
method: Option<Method>,
|
||||||
) -> syn::Result<Self> {
|
) -> syn::Result<Self> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
format!(
|
format!(
|
||||||
r#"invalid server definition, expected #[{}("<some path>")]"#,
|
r#"invalid service definition, expected #[{}("<some path>")]"#,
|
||||||
guard.as_str().to_ascii_lowercase()
|
method
|
||||||
|
.map(|it| it.as_str())
|
||||||
|
.unwrap_or("route")
|
||||||
|
.to_ascii_lowercase()
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let ast: syn::ItemFn = syn::parse(input)?;
|
let ast: syn::ItemFn = syn::parse(input)?;
|
||||||
let name = ast.sig.ident.clone();
|
let name = ast.sig.ident.clone();
|
||||||
|
|
||||||
let args = Args::new(args)?;
|
let methods = method.into_iter().collect();
|
||||||
|
let args = Args::new(args, methods)?;
|
||||||
if guard == GuardType::Multi && args.methods.is_empty() {
|
if args.methods.is_empty() {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
"The #[route(..)] macro requires at least one `method` attribute",
|
"The #[route(..)] macro requires at least one `method` attribute",
|
||||||
|
@ -240,7 +239,6 @@ impl Route {
|
||||||
args,
|
args,
|
||||||
ast,
|
ast,
|
||||||
resource_type,
|
resource_type,
|
||||||
guard,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +247,6 @@ impl ToTokens for Route {
|
||||||
fn to_tokens(&self, output: &mut TokenStream2) {
|
fn to_tokens(&self, output: &mut TokenStream2) {
|
||||||
let Self {
|
let Self {
|
||||||
name,
|
name,
|
||||||
guard,
|
|
||||||
ast,
|
ast,
|
||||||
args:
|
args:
|
||||||
Args {
|
Args {
|
||||||
|
@ -261,21 +258,22 @@ impl ToTokens for Route {
|
||||||
resource_type,
|
resource_type,
|
||||||
} = self;
|
} = self;
|
||||||
let resource_name = name.to_string();
|
let resource_name = name.to_string();
|
||||||
let mut methods = methods.iter();
|
let method_guards = {
|
||||||
|
let mut others = methods.iter();
|
||||||
let method_guards = if *guard == GuardType::Multi {
|
|
||||||
// unwrapping since length is checked to be at least one
|
// unwrapping since length is checked to be at least one
|
||||||
let first = methods.next().unwrap();
|
let first = others.next().unwrap();
|
||||||
|
|
||||||
|
if methods.len() > 1 {
|
||||||
quote! {
|
quote! {
|
||||||
.guard(
|
.guard(
|
||||||
actix_web::guard::Any(actix_web::guard::#first())
|
actix_web::guard::Any(actix_web::guard::#first())
|
||||||
#(.or(actix_web::guard::#methods()))*
|
#(.or(actix_web::guard::#others()))*
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
.guard(actix_web::guard::#guard())
|
.guard(actix_web::guard::#first())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -302,13 +300,13 @@ impl ToTokens for Route {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn generate(
|
pub(crate) fn with_method(
|
||||||
|
method: Option<Method>,
|
||||||
args: TokenStream,
|
args: TokenStream,
|
||||||
input: TokenStream,
|
input: TokenStream,
|
||||||
guard: GuardType,
|
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let args = parse_macro_input!(args as syn::AttributeArgs);
|
let args = parse_macro_input!(args as syn::AttributeArgs);
|
||||||
match Route::new(args, input, guard) {
|
match Route::new(args, input, method) {
|
||||||
Ok(route) => route.into_token_stream().into(),
|
Ok(route) => route.into_token_stream().into(),
|
||||||
Err(err) => err.to_compile_error().into(),
|
Err(err) => err.to_compile_error().into(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue