xitca_codegen/
lib.rs

1mod error;
2mod route;
3mod service;
4mod state;
5
6use proc_macro::TokenStream;
7use syn::{Error, ImplItem, ImplItemFn, spanned::Spanned};
8
9#[proc_macro_derive(State, attributes(borrow))]
10pub fn state_impl(item: TokenStream) -> TokenStream {
11    let item = syn::parse_macro_input!(item);
12    state::state(item).unwrap_or_else(|e| e.to_compile_error().into())
13}
14
15/// attribute macro for `xitca-web` application.
16///
17/// # Pattern
18/// ```plain
19/// #[route("path", method = <method>[, attributes])]
20/// ```
21///
22/// # Attributes
23/// - `"path"`: string literal represent path register to http router.
24///   `"/foo"` for example.  
25/// - `method = <method>`: function path of http method register to http router.
26///   `method = get` for example.
27/// - `enclosed = <type>`: typed middleware applied to route.
28/// - `enclosed_fn = <async function>`: async function as middleware applied to route
29/// ```
30#[proc_macro_attribute]
31pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
32    let attr = syn::parse_macro_input!(attr);
33    let item = syn::parse_macro_input!(item);
34    route::route(attr, item).unwrap_or_else(|e| e.to_compile_error().into())
35}
36
37#[proc_macro_attribute]
38pub fn error_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
39    let item = syn::parse_macro_input!(item);
40    error::error(attr, item).unwrap_or_else(|e| e.to_compile_error().into())
41}
42
43#[proc_macro_attribute]
44pub fn middleware_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
45    let item = syn::parse_macro_input!(item);
46    service::middleware(attr, item).unwrap_or_else(|e| e.to_compile_error().into())
47}
48
49#[proc_macro_attribute]
50pub fn service_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
51    let item = syn::parse_macro_input!(item);
52    service::service(attr, item).unwrap_or_else(|e| e.to_compile_error().into())
53}
54
55fn find_async_method<'a>(items: &'a [ImplItem], ident_str: &str) -> Option<Result<&'a ImplItemFn, Error>> {
56    for item in items.iter() {
57        if let ImplItem::Fn(func) = item {
58            if func.sig.ident.to_string().as_str() == ident_str {
59                if func.sig.asyncness.is_none() {
60                    return Some(Err(Error::new(
61                        func.span(),
62                        format!("{ident_str} method must be async fn"),
63                    )));
64                }
65
66                return Some(Ok(func));
67            }
68        }
69    }
70
71    None
72}