From c1877c2707ebab9221f163b5c5c886ad2bc19148 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Fri, 10 Apr 2020 13:28:50 +0600 Subject: [PATCH] restore web proc macros --- Cargo.toml | 16 +++--- ntex-macros/CHANGES.md | 4 +- ntex-macros/Cargo.toml | 4 +- ntex-macros/src/lib.rs | 48 ++++++++--------- ntex-macros/src/route.rs | 92 ++++++++++++++------------------- ntex-macros/tests/test_macro.rs | 90 ++++++++++++++++---------------- ntex/Cargo.toml | 1 + ntex/examples/basic.rs | 11 ++-- ntex/examples/uds.rs | 9 ++-- ntex/src/web/mod.rs | 11 ++++ 10 files changed, 139 insertions(+), 147 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d9a03af1..1969aeff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,14 @@ members = [ "ntex-rt", "ntex-rt-macros", "ntex-service", + "ntex-macros", ] -#[patch.crates-io] -#ntex = { path = "ntex" } -#ntex-codec = { path = "ntex-codec" } -#ntex-router = { path = "ntex-router" } -#ntex-rt = { path = "ntex-rt" } -#ntex-rt-macros = { path = "ntex-rt-macros" } -#ntex-service = { path = "ntex-service" } +[patch.crates-io] +ntex = { path = "ntex" } +ntex-codec = { path = "ntex-codec" } +ntex-router = { path = "ntex-router" } +ntex-rt = { path = "ntex-rt" } +ntex-rt-macros = { path = "ntex-rt-macros" } +ntex-service = { path = "ntex-service" } +ntex-macros = { path = "ntex-macros" } \ No newline at end of file diff --git a/ntex-macros/CHANGES.md b/ntex-macros/CHANGES.md index 54c13042..45d4a037 100644 --- a/ntex-macros/CHANGES.md +++ b/ntex-macros/CHANGES.md @@ -1,5 +1,5 @@ # Changes -## [0.1.0] - 2020-xx-xx +## [0.1.0] - 2020-04-10 -* Fork +* Fork to ntex namespace diff --git a/ntex-macros/Cargo.toml b/ntex-macros/Cargo.toml index c010631d..f9c5bc52 100644 --- a/ntex-macros/Cargo.toml +++ b/ntex-macros/Cargo.toml @@ -16,5 +16,5 @@ syn = { version = "^1", features = ["full", "parsing"] } proc-macro2 = "^1" [dev-dependencies] -ntex = { path = "../ntex/" } -futures = { version = "0.3.1" } +ntex = "0.1.6" +futures = "0.3.4" diff --git a/ntex-macros/src/lib.rs b/ntex-macros/src/lib.rs index 89e528fb..7a7295af 100644 --- a/ntex-macros/src/lib.rs +++ b/ntex-macros/src/lib.rs @@ -1,26 +1,27 @@ #![recursion_limit = "512"] //! web macros module //! -//! Generators for routes and scopes +//! Generators for routes //! //! ## Route //! //! Macros: //! -//! - [web_get](attr.get.html) -//! - [web_post](attr.post.html) -//! - [web_put](attr.put.html) -//! - [web_delete](attr.delete.html) -//! - [web_head](attr.head.html) -//! - [web_connect](attr.connect.html) -//! - [web_options](attr.options.html) -//! - [web_trace](attr.trace.html) -//! - [web_patch](attr.patch.html) +//! - [get](attr.web_get.html) +//! - [post](attr.web_post.html) +//! - [put](attr.web_put.html) +//! - [delete](attr.web_delete.html) +//! - [head](attr.web_head.html) +//! - [connect](attr.web_connect.html) +//! - [options](attr.web_options.html) +//! - [trace](attr.web_trace.html) +//! - [patch](attr.web_patch.html) //! //! ### Attributes: //! //! - `"path"` - Raw literal string with path for which to register handle. Mandatory. -//! - `guard="function_name"` - Registers function as guard using `ntex::web::guard::fn_guard` +//! - `guard = "function_name"` - Registers function as guard using `ntex::web::guard::fn_guard` +//! - `error = "ErrorRenderer"` - Register handler for specified error renderer //! //! ## Notes //! @@ -30,11 +31,11 @@ //! ## Example: //! //! ```rust -//! use ntex::web::{get, HttpResponse}; +//! use ntex::web::{get, Error, HttpResponse}; //! use futures::{future, Future}; //! //! #[get("/test")] -//! async fn async_test() -> Result { +//! async fn async_test() -> Result { //! Ok(HttpResponse::Ok().finish()) //! } //! ``` @@ -53,11 +54,12 @@ use syn::parse_macro_input; /// ## Attributes: /// /// - `"path"` - Raw literal string with path for which to register handler. Mandatory. -/// - `guard="function_name"` - Registers function as guard using `ntex::web::guard::fn_guard` +/// - `guard = "function_name"` - Registers function as guard using `ntex::web::guard::fn_guard` +/// - `error = "ErrorRenderer"` - Register handler for different error renderer #[proc_macro_attribute] pub fn web_get(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as syn::AttributeArgs); - let gen = match route::Route::new(args, input, route::GuardType::Get) { + let gen = match route::Route::new(args, input, route::MethodType::Get) { Ok(gen) => gen, Err(err) => return err.to_compile_error().into(), }; @@ -72,7 +74,7 @@ pub fn web_get(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn web_post(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as syn::AttributeArgs); - let gen = match route::Route::new(args, input, route::GuardType::Post) { + let gen = match route::Route::new(args, input, route::MethodType::Post) { Ok(gen) => gen, Err(err) => return err.to_compile_error().into(), }; @@ -87,7 +89,7 @@ pub fn web_post(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn web_put(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as syn::AttributeArgs); - let gen = match route::Route::new(args, input, route::GuardType::Put) { + let gen = match route::Route::new(args, input, route::MethodType::Put) { Ok(gen) => gen, Err(err) => return err.to_compile_error().into(), }; @@ -102,7 +104,7 @@ pub fn web_put(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn web_delete(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as syn::AttributeArgs); - let gen = match route::Route::new(args, input, route::GuardType::Delete) { + let gen = match route::Route::new(args, input, route::MethodType::Delete) { Ok(gen) => gen, Err(err) => return err.to_compile_error().into(), }; @@ -117,7 +119,7 @@ pub fn web_delete(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn web_head(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as syn::AttributeArgs); - let gen = match route::Route::new(args, input, route::GuardType::Head) { + let gen = match route::Route::new(args, input, route::MethodType::Head) { Ok(gen) => gen, Err(err) => return err.to_compile_error().into(), }; @@ -132,7 +134,7 @@ pub fn web_head(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn web_connect(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as syn::AttributeArgs); - let gen = match route::Route::new(args, input, route::GuardType::Connect) { + let gen = match route::Route::new(args, input, route::MethodType::Connect) { Ok(gen) => gen, Err(err) => return err.to_compile_error().into(), }; @@ -147,7 +149,7 @@ pub fn web_connect(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn web_options(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as syn::AttributeArgs); - let gen = match route::Route::new(args, input, route::GuardType::Options) { + let gen = match route::Route::new(args, input, route::MethodType::Options) { Ok(gen) => gen, Err(err) => return err.to_compile_error().into(), }; @@ -162,7 +164,7 @@ pub fn web_options(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn web_trace(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as syn::AttributeArgs); - let gen = match route::Route::new(args, input, route::GuardType::Trace) { + let gen = match route::Route::new(args, input, route::MethodType::Trace) { Ok(gen) => gen, Err(err) => return err.to_compile_error().into(), }; @@ -177,7 +179,7 @@ pub fn web_trace(args: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn web_patch(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as syn::AttributeArgs); - let gen = match route::Route::new(args, input, route::GuardType::Patch) { + let gen = match route::Route::new(args, input, route::MethodType::Patch) { Ok(gen) => gen, Err(err) => return err.to_compile_error().into(), }; diff --git a/ntex-macros/src/route.rs b/ntex-macros/src/route.rs index da248770..8d69eb9e 100644 --- a/ntex-macros/src/route.rs +++ b/ntex-macros/src/route.rs @@ -1,10 +1,10 @@ use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{quote, ToTokens, TokenStreamExt}; -use syn::{AttributeArgs, Ident, NestedMeta}; +use syn::{AttributeArgs, Ident, NestedMeta, Path}; #[derive(PartialEq)] -pub enum GuardType { +pub enum MethodType { Get, Post, Put, @@ -16,23 +16,23 @@ pub enum GuardType { Patch, } -impl GuardType { +impl MethodType { fn as_str(&self) -> &'static str { match self { - GuardType::Get => "Get", - GuardType::Post => "Post", - GuardType::Put => "Put", - GuardType::Delete => "Delete", - GuardType::Head => "Head", - GuardType::Connect => "Connect", - GuardType::Options => "Options", - GuardType::Trace => "Trace", - GuardType::Patch => "Patch", + MethodType::Get => "Get", + MethodType::Post => "Post", + MethodType::Put => "Put", + MethodType::Delete => "Delete", + MethodType::Head => "Head", + MethodType::Connect => "Connect", + MethodType::Options => "Options", + MethodType::Trace => "Trace", + MethodType::Patch => "Patch", } } } -impl ToTokens for GuardType { +impl ToTokens for MethodType { fn to_tokens(&self, stream: &mut TokenStream2) { let ident = self.as_str(); let ident = Ident::new(ident, Span::call_site()); @@ -43,12 +43,14 @@ impl ToTokens for GuardType { struct Args { path: syn::LitStr, guards: Vec, + error: Path, } impl Args { fn new(args: AttributeArgs) -> syn::Result { let mut path = None; let mut guards = Vec::new(); + let mut error: Option = None; for arg in args { match arg { NestedMeta::Lit(syn::Lit::Str(lit)) => match path { @@ -72,10 +74,19 @@ impl Args { "Attribute guard expects literal string!", )); } + } else if nv.path.is_ident("error") { + if let syn::Lit::Str(lit) = nv.lit { + error = Some(syn::parse_str(&lit.value())?); + } else { + return Err(syn::Error::new_spanned( + nv.lit, + "Attribute error expects type path!", + )); + } } else { return Err(syn::Error::new_spanned( nv.path, - "Unknown attribute key is specified. Allowed: guard", + "Unknown attribute key is specified. Allowed: guard or error", )); } } @@ -87,6 +98,8 @@ impl Args { Ok(Args { path: path.unwrap(), guards, + error: error + .unwrap_or_else(|| syn::parse_str("ntex::web::DefaultError").unwrap()), }) } } @@ -95,21 +108,21 @@ pub struct Route { name: syn::Ident, args: Args, ast: syn::ItemFn, - guard: GuardType, + method: MethodType, } impl Route { pub fn new( args: AttributeArgs, input: TokenStream, - guard: GuardType, + method: MethodType, ) -> syn::Result { if args.is_empty() { return Err(syn::Error::new( Span::call_site(), format!( r#"invalid server definition, expected #[{}("")]"#, - guard.as_str().to_ascii_lowercase() + method.as_str().to_ascii_lowercase() ), )); } @@ -121,64 +134,35 @@ impl Route { name, args, ast, - guard, + method, }) } pub fn generate(&self) -> TokenStream { let name = &self.name; let resource_name = name.to_string(); - let guard = &self.guard; let ast = &self.ast; let path = &self.args.path; let extra_guards = &self.args.guards; - - let args: Vec<_> = ast - .sig - .inputs - .iter() - .filter(|item| match item { - syn::FnArg::Receiver(_) => false, - syn::FnArg::Typed(_) => true, - }) - .map(|item| match item { - syn::FnArg::Receiver(_) => panic!(), - syn::FnArg::Typed(ref pt) => pt.ty.clone(), - }) - .collect(); - - let assert_responder: syn::Path = syn::parse_str( - format!( - "ntex::web::dev::__assert_handler{}", - if args.is_empty() { - "".to_string() - } else { - format!("{}", args.len()) - } - ) - .as_str(), - ) - .unwrap(); + let error = &self.args.error; + let method = &self.method; let stream = quote! { #[allow(non_camel_case_types)] pub struct #name; - impl<__E: 'static> ntex::web::dev::HttpServiceFactory<__E> for #name - where __E: ntex::web::error::ErrorRenderer + impl ntex::web::dev::WebServiceFactory<#error> for #name { - fn register(self, __config: &mut ntex::web::dev::AppService<__E>) { - #(ntex::web::dev::__assert_extractor::<__E, #args>();)* - + fn register(self, __config: &mut ntex::web::dev::WebServiceConfig<#error>) { #ast let __resource = ntex::web::Resource::new(#path) .name(#resource_name) - .guard(ntex::web::guard::#guard()) + .guard(ntex::web::guard::#method()) #(.guard(ntex::web::guard::fn_guard(#extra_guards)))* - .to(#assert_responder(#name)); + .to(#name); - ntex::web::dev::HttpServiceFactory::register(__resource, __config) + ntex::web::dev::WebServiceFactory::register(__resource, __config) } } }; diff --git a/ntex-macros/tests/test_macro.rs b/ntex-macros/tests/test_macro.rs index 3e49668e..50f1ea77 100644 --- a/ntex-macros/tests/test_macro.rs +++ b/ntex-macros/tests/test_macro.rs @@ -1,82 +1,80 @@ use futures::{future, Future}; -use ntex::http::{Error, Method, StatusCode}; -use ntex::web::{test, types::Path, App, HttpResponse, Responder}; -use ntex_web_macros::{connect, delete, get, head, options, patch, post, put, trace}; +use ntex::http::{Method, StatusCode}; +use ntex::web::{test, types::Path, App, Error, HttpResponse, HttpResponseBuilder}; +use ntex_macros::{ + web_connect, web_delete, web_get, web_head, web_options, web_patch, web_post, + web_put, web_trace, +}; // Make sure that we can name function as 'config' -#[get("/config")] -async fn config() -> impl Responder { - HttpResponse::Ok() +#[web_get("/config")] +async fn config() -> HttpResponse { + HttpResponse::Ok().finish() } -#[get("/test")] -async fn test_handler() -> impl Responder { - HttpResponse::Ok() +#[web_get("/test")] +async fn test_handler() -> HttpResponse { + HttpResponse::Ok().finish() } -#[put("/test")] -async fn put_test() -> impl Responder { - HttpResponse::Created() +#[web_put("/test")] +async fn put_test() -> HttpResponse { + HttpResponse::Created().finish() } -#[patch("/test")] -async fn patch_test() -> impl Responder { - HttpResponse::Ok() +#[web_patch("/test")] +async fn patch_test() -> HttpResponse { + HttpResponse::Ok().finish() } -#[post("/test")] -async fn post_test() -> impl Responder { - HttpResponse::NoContent() +#[web_post("/test")] +async fn post_test() -> HttpResponse { + HttpResponse::NoContent().finish() } -#[head("/test")] -async fn head_test() -> impl Responder { - HttpResponse::Ok() +#[web_head("/test")] +async fn head_test() -> HttpResponse { + HttpResponse::Ok().finish() } -#[connect("/test")] -async fn connect_test() -> impl Responder { - HttpResponse::Ok() +#[web_connect("/test")] +async fn connect_test() -> HttpResponse { + HttpResponse::Ok().finish() } -#[options("/test")] -async fn options_test() -> impl Responder { - HttpResponse::Ok() +#[web_options("/test")] +async fn options_test() -> HttpResponse { + HttpResponse::Ok().finish() } -#[trace("/test")] -async fn trace_test() -> impl Responder { - HttpResponse::Ok() +#[web_trace("/test")] +async fn trace_test() -> HttpResponse { + HttpResponse::Ok().finish() } -#[get("/test")] +#[web_get("/test")] fn auto_async() -> impl Future> { future::ok(HttpResponse::Ok().finish()) } -#[get("/test")] -fn auto_sync() -> impl Future> { - future::ok(HttpResponse::Ok().finish()) -} - -#[put("/test/{param}")] -async fn put_param_test(_: Path) -> impl Responder { +#[web_put("/test/{param}")] +async fn put_param_test(_: Path) -> HttpResponseBuilder { HttpResponse::Created() } -#[delete("/test/{param}")] -async fn delete_param_test(_: Path) -> impl Responder { +#[web_delete("/test/{param}")] +async fn delete_param_test(_: Path) -> HttpResponseBuilder { HttpResponse::NoContent() } -#[get("/test/{param}")] -async fn get_param_test(_: Path) -> impl Responder { - HttpResponse::Ok() +#[web_get("/test/{param}")] +async fn get_param_test(_: Path) -> HttpResponse { + HttpResponse::Ok().finish() } #[ntex::test] async fn test_params() { - let srv = test::start(|| { + let srv = test::server(|| { App::new() .service(get_param_test) .service(put_param_test) @@ -98,7 +96,7 @@ async fn test_params() { #[ntex::test] async fn test_body() { - let srv = test::start(|| { + let srv = test::server(|| { App::new() .service(post_test) .service(put_test) @@ -150,7 +148,7 @@ async fn test_body() { #[ntex::test] async fn test_auto_async() { - let srv = test::start(|| App::new().service(auto_async)); + let srv = test::server(|| App::new().service(auto_async)); let request = srv.request(Method::GET, srv.url("/test")); let response = request.send().await.unwrap(); diff --git a/ntex/Cargo.toml b/ntex/Cargo.toml index afd6bb51..65c3c233 100644 --- a/ntex/Cargo.toml +++ b/ntex/Cargo.toml @@ -41,6 +41,7 @@ ntex-rt = "0.1" ntex-rt-macros = "0.1" ntex-router = "0.3.2" ntex-service = "0.1" +ntex-macros = "0.1" actix-threadpool = "0.3.1" base64 = "0.12" diff --git a/ntex/examples/basic.rs b/ntex/examples/basic.rs index 6bcbd582..87d5a571 100644 --- a/ntex/examples/basic.rs +++ b/ntex/examples/basic.rs @@ -1,7 +1,7 @@ use ntex::http; use ntex::web::{self, middleware, App, HttpRequest, HttpResponse, HttpServer}; -// #[get("/resource1/{name}/index.html")] +#[web::get("/resource1/{name}/index.html")] async fn index(req: HttpRequest, name: web::types::Path) -> String { println!("REQ: {:?}", req); format!("Hello: {}!\r\n", name) @@ -12,7 +12,7 @@ async fn index_async(req: HttpRequest) -> &'static str { "Hello world!\r\n" } -// #[get("/")] +#[web::get("/")] async fn no_params() -> &'static str { "Hello world!\r\n" } @@ -24,11 +24,8 @@ async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() - // .wrap(middleware::Logger::default()) - .service(web::resource("/resource1/{name}/index.html").to(index)) - .service(web::resource("/").route(web::get().to(no_params))) - // .service(index) - // .service(no_params) + .wrap(middleware::Logger::default()) + .service((index, no_params)) .service( web::resource("/resource2/index.html") .wrap( diff --git a/ntex/examples/uds.rs b/ntex/examples/uds.rs index 058bc33f..0c34fddd 100644 --- a/ntex/examples/uds.rs +++ b/ntex/examples/uds.rs @@ -1,6 +1,6 @@ use ntex::web::{self, middleware, App, Error, HttpRequest, HttpResponse, HttpServer}; -// #[get("/resource1/{name}/index.html")] +#[web::get("/resource1/{name}/index.html")] async fn index(req: HttpRequest, name: web::types::Path) -> String { println!("REQ: {:?}", req); format!("Hello: {}!\r\n", name) @@ -11,7 +11,7 @@ async fn index_async(req: HttpRequest) -> Result<&'static str, Error> { Ok("Hello world!\r\n") } -// #[get("/")] +#[web::get("/")] async fn no_params() -> &'static str { "Hello world!\r\n" } @@ -26,10 +26,7 @@ async fn main() -> std::io::Result<()> { App::new() .wrap(middleware::DefaultHeaders::new().header("X-Version", "0.2")) .wrap(middleware::Logger::default()) - .service(web::resource("/resource1/{name}/index.html").to(index)) - .service(web::resource("/").route(web::get().to(no_params))) - // .service(index) - // .service(no_params) + .service((index, no_params)) .service( web::resource("/resource2/index.html") .wrap( diff --git a/ntex/src/web/mod.rs b/ntex/src/web/mod.rs index b37229b1..c5e70496 100644 --- a/ntex/src/web/mod.rs +++ b/ntex/src/web/mod.rs @@ -87,6 +87,17 @@ pub mod test; pub mod types; mod util; +// re-export proc macro +pub use ntex_macros::web_connect as connect; +pub use ntex_macros::web_delete as delete; +pub use ntex_macros::web_get as get; +pub use ntex_macros::web_head as head; +pub use ntex_macros::web_options as options; +pub use ntex_macros::web_patch as patch; +pub use ntex_macros::web_post as post; +pub use ntex_macros::web_put as put; +pub use ntex_macros::web_trace as trace; + pub use crate::http::Response as HttpResponse; pub use crate::http::ResponseBuilder as HttpResponseBuilder;