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}