actix_web_cute_codegen/
lib.rs

1#![recursion_limit = "512"]
2//! Actix-web codegen module
3//!
4//! Generators for routes and scopes
5//!
6//! ## Route
7//!
8//! Macros:
9//!
10//! - [handler](attr.handler.html)
11//! - [get](attr.get.html)
12//! - [post](attr.post.html)
13//! - [put](attr.put.html)
14//! - [delete](attr.delete.html)
15//!
16//! ### Attributes:
17//!
18//! - `"path"` - Raw literal string with path for which to register handle. Mandatory.
19//! - `async` - Attribute to indicate that registered function is asynchronous.
20//! - `guard="function_name"` - Registers function as guard using `actix_web::guard::fn_guard`
21//!
22//! ## Scope
23//!
24//! Macros:
25//!
26//! - [scope](attr.scope.html)
27//!
28//! ### Attributes:
29//!
30//! - `"path"` - Raw literal string with path for which to register handle. Mandatory.
31//! - `guard="function_name"` - Registers function as guard using `actix_web::guard::fn_guard`
32//!
33//! ## Notes
34//!
35//! Function name can be specified as any expression that is going to be accessible to the generate
36//! code (e.g `my_guard` or `my_module::my_guard`)
37//!
38//! ## Example:
39//!
40//! ```rust
41//! use actix_web::HttpResponse;
42//! use actix_web_cute_codegen::get;
43//! use futures::{future, Future};
44//!
45//! #[get("/test", async)]
46//! fn async_test() -> impl Future<Item=HttpResponse, Error=actix_web::Error> {
47//!     future::ok(HttpResponse::Ok().finish())
48//! }
49//! ```
50
51extern crate proc_macro;
52
53mod route;
54mod scope;
55
56use proc_macro::TokenStream;
57use syn::parse_macro_input;
58
59/// Creates route handler without attached method guard.
60///
61/// Syntax: `#[handler("path"[, attributes])]`
62///
63/// ## Attributes:
64///
65/// - `"path"` - Raw literal string with path for which to register handler. Mandatory.
66/// - `async` - Attribute to indicate that registered function is asynchronous.
67/// - `guard="function_name"` - Registers function as guard using `actix_web::guard::fn_guard`
68#[proc_macro_attribute]
69pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
70    let args = parse_macro_input!(args as syn::AttributeArgs);
71    let gen = route::Args::new(&args, input, route::GuardType::Get);
72    gen.generate()
73}
74
75/// Creates route handler with `GET` method guard.
76///
77/// Syntax: `#[get("path"[, attributes])]`
78///
79/// Attributes are the same as in [handler](attr.handler.html)
80#[proc_macro_attribute]
81pub fn get(args: TokenStream, input: TokenStream) -> TokenStream {
82    let args = parse_macro_input!(args as syn::AttributeArgs);
83    let gen = route::Args::new(&args, input, route::GuardType::Get);
84    gen.generate()
85}
86
87/// Creates route handler with `POST` method guard.
88///
89/// Syntax: `#[post("path"[, attributes])]`
90///
91/// Attributes are the same as in [handler](attr.handler.html)
92#[proc_macro_attribute]
93pub fn post(args: TokenStream, input: TokenStream) -> TokenStream {
94    let args = parse_macro_input!(args as syn::AttributeArgs);
95    let gen = route::Args::new(&args, input, route::GuardType::Post);
96    gen.generate()
97}
98
99/// Creates route handler with `PUT` method guard.
100///
101/// Syntax: `#[put("path"[, attributes])]`
102///
103/// Attributes are the same as in [handler](attr.handler.html)
104#[proc_macro_attribute]
105pub fn put(args: TokenStream, input: TokenStream) -> TokenStream {
106    let args = parse_macro_input!(args as syn::AttributeArgs);
107    let gen = route::Args::new(&args, input, route::GuardType::Put);
108    gen.generate()
109}
110
111/// Creates route handler with `DELETE` method guard.
112///
113/// Syntax: `#[delete("path"[, attributes])]`
114///
115/// Attributes are the same as in [handler](attr.handler.html)
116#[proc_macro_attribute]
117pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream {
118    let args = parse_macro_input!(args as syn::AttributeArgs);
119    let gen = route::Args::new(&args, input, route::GuardType::Delete);
120    gen.generate()
121}
122
123/// Generates scope
124///
125/// Syntax: `#[scope("path"[, attributes])]`
126///
127/// Due to current limitation it cannot be applied to modules themself.
128/// Instead one should create const variable that contains module code.
129///
130/// ## Attributes:
131///
132/// - `"path"` - Raw literal string with path for which to register handler. Mandatory.
133/// - `hook="function_name"` - Registers function to be run on scope before registering everything else.
134/// - `guard="function_name"` - Registers function as guard using `actix_web::guard::fn_guard`
135/// - `hanlder="function_name"` - Registers route hanlder as part of scope.
136///
137/// ## Special members:
138///
139/// - `#[hook]` functions - are going to be run on scope before registering everything else
140/// - `#[guard]` functions - specifies function to be passed to `guard_fn`.
141/// - `init` - Scope initialization function. Used as `hook`
142/// - `default_resource` - function will be used as default method to the scope.
143///
144/// # Example
145///
146/// ```rust
147/// use actix_web_cute_codegen::{scope};
148///
149/// #[scope("/scope")]
150/// const mod_inner: () = {
151///     use actix_web_cute_codegen::{get, hook};
152///     use actix_web::{HttpResponse, Responder};
153///     use futures::{Future, future};
154///
155///     #[get("/test")]
156///     pub fn test() -> impl Responder {
157///         HttpResponse::Ok()
158///     }
159///
160///     #[get("/test_async")]
161///     pub fn auto_sync() -> impl Future<Item=HttpResponse, Error=actix_web::Error> {
162///         future::ok(HttpResponse::Ok().finish())
163///     }
164///
165///     ///Special function to initialize scope. Called as hook before routes registration.
166///     pub fn init<P: 'static>(scope: actix_web::Scope<P>) -> actix_web::Scope<P> {
167///         scope
168///     }
169///
170///     pub fn default_resource<P: 'static>(res: actix_web::Resource<P>) -> actix_web::Resource<P> {
171///         res.to(|| HttpResponse::InternalServerError())
172///     }
173///
174/// };
175/// ```
176///
177/// # Note
178///
179/// Internally the macro generate struct with name of scope (e.g. `mod_inner`)
180/// And create public module as `<name>_scope`
181#[proc_macro_attribute]
182pub fn scope(args: TokenStream, input: TokenStream) -> TokenStream {
183    let args = parse_macro_input!(args as syn::AttributeArgs);
184    match args.len() {
185        0 => scope::attr::ImplScope::new(input).generate(),
186        _ => scope::attr::Args::new(&args, input).generate(),
187    }
188}
189
190///Marks function as guard
191#[proc_macro_attribute]
192pub fn guard(_args: TokenStream, input: TokenStream) -> TokenStream {
193    input
194}
195
196///Marks function as hook.
197///
198///Depending on context it allows to run custom code on item
199///before it registers stuff
200#[proc_macro_attribute]
201pub fn hook(_args: TokenStream, input: TokenStream) -> TokenStream {
202    input
203}
204
205///Generates Application
206///
207///Similar to [scope](attr.scope.html) macro
208///
209///## Example
210///
211///```rust
212///use futures::{Future, future};
213///use actix_web_cute_codegen::{get, scope, Scope};
214///
215///#[get("/test")]
216///fn test() -> impl actix_web::Responder {
217///    actix_web::HttpResponse::Ok()
218///}
219///
220///#[derive(Scope)]
221///#[path="/my_scope"]
222///pub struct MyScope {
223///    #[service]
224///    test: test,
225///    #[guard]
226///    guard: actix_web::guard::AnyGuard,
227///}
228///
229///#[scope]
230///impl MyScope {
231///    fn new() -> Self {
232///        Self {
233///            test: test,
234///            guard: actix_web::guard::Any(actix_web::guard::Get()).or(actix_web::guard::Post()),
235///        }
236///    }
237///
238///    //Special member to act as hook
239///    pub fn init<P: 'static>(scope: actix_web::Scope<P>) -> actix_web::Scope<P> {
240///        scope
241///    }
242///
243///    //Mark any function as initialization of scope
244///    #[hook]
245///    pub fn init_scope<P: 'static>(scope: actix_web::Scope<P>) -> actix_web::Scope<P> {
246///        scope
247///    }
248///
249///
250///    pub fn init_scope_unused<P: 'static>(scope: actix_web::Scope<P>) -> actix_web::Scope<P> {
251///        scope
252///    }
253///
254///    #[get("/test_async")]
255///    pub fn test_async() -> impl Future<Item=actix_web::HttpResponse, Error=actix_web::Error> {
256///        future::ok(actix_web::HttpResponse::Ok().finish())
257///    }
258///
259///    pub fn default_resource<P: 'static>(res: actix_web::Resource<P>) -> actix_web::Resource<P> {
260///        res.to(|| actix_web::HttpResponse::InternalServerError())
261///    }
262///}
263///```
264#[proc_macro_derive(Scope, attributes(path, service, guard))]
265pub fn parser_derive(input: TokenStream) -> TokenStream {
266    let ast: syn::DeriveInput = syn::parse(input).unwrap();
267    let gen = scope::derive::Args::new(ast);
268    gen.generate()
269}