1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
extern crate proc_macro;

use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::parse_macro_input;

mod cookies;
mod forms;
mod models;
mod route;
mod util;

#[proc_macro_attribute]
pub fn cookie(meta: TokenStream, item: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(item as syn::ItemStruct);
    let meta = parse_macro_input!(meta as cookies::CookieMeta);
    let cookie = cookies::cookie(&meta, &ast);
    let mut tokens = ast.to_token_stream();
    tokens.extend(cookie);
    TokenStream::from(tokens)
}

#[proc_macro_attribute]
pub fn form(meta: TokenStream, item: TokenStream) -> TokenStream {
    let mut ast = parse_macro_input!(item as syn::ItemStruct);
    let meta = parse_macro_input!(meta as forms::FormMeta);
    let display = forms::form(&meta, &mut ast);
    let mut tokens = ast.to_token_stream();
    tokens.extend(display);
    TokenStream::from(tokens)
}

/// Implement a request handler wrapper for the annotated function
///
/// The attribute takes allowed methods as its arguments:
///
/// ```ignore
/// /// This handler will immediately return a `405 Method not allowed`
/// /// error for all request methods other than `GET`
/// #[handler(GET)]
/// fn hello(_: &App) -> Result<Response<String>, Error> {
///     Ok(Response::builder()
///         .status(StatusCode::OK)
///         .body("Hello, world".into())
///         .unwrap())
/// }
/// ```
///
/// The first argument of the function must be a reference to an implementer of
/// the `Application` trait (the implementor may also be wrapped in an `Arc`).
/// All unannotated arguments must be of types that implement the `FromContext`
/// trait for the `Application` type used in the first argument. This includes
/// `&http::request::Parts`, the `Request`'s headers and any number of types
/// that can represent a path component from the URI:
///
/// * `&[u8]` for the bytes representation of the path component
/// * `Cow<'_, str>`
/// * `String`
/// * Numeric types (`i8`, `u8`, `i16`, `u16`, ..., `isize`, `usize`, `f32`, `f64`)
/// * `bool` and `char`
/// * If the `hyper` feature is enabled, `hyper::body::Body`
///   (only if `Application::RequestBody` is also `Body`)
///
/// Each of these types can be wrapped in `Option` for optional path components.
/// Additionally, there are two attributes that may be used on handler arguments:
///
/// * `#[rest]`: a `&str` representing the part of the request path not yet consumed by routing
/// * `#[query]`: a type that implements `Deserialize`, and will be used to deserialize the URI query
///
/// This macro will generate a module that contains a `call()` function mirroring
/// the original function, and you may rely on this behavior (for example, for testing).
///
/// ```ignore
/// mod hello {
///    use super::*;
///    /// ... some internals hidden ...
///    pub(super) async fn call(_: &App) -> Result<Response<Body>, Error> {
///        Ok(Response::builder()
///            .status(StatusCode::OK)
///            .body("Hello, world".into())
///            .unwrap())
///    }
/// }
/// ```
#[proc_macro_attribute]
pub fn handler(meta: TokenStream, item: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(item as syn::ItemFn);
    let methods = parse_macro_input!(meta as route::HandlerMethods).methods;
    route::handler(&methods, ast)
}

#[proc_macro_attribute]
pub fn scope(_: TokenStream, item: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(item as syn::ItemFn);
    route::scope(ast)
}

#[proc_macro]
pub fn route(item: TokenStream) -> TokenStream {
    let mut ast = parse_macro_input!(item as syn::ExprMatch);
    route::route(&mut ast);
    quote!(#ast).into()
}

#[proc_macro_derive(ToField, attributes(option))]
pub fn derive_to_field(item: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(item as syn::DeriveInput);
    TokenStream::from(forms::to_field(ast))
}

#[proc_macro_attribute]
pub fn model(_: TokenStream, item: TokenStream) -> TokenStream {
    let mut ast = parse_macro_input!(item as syn::ItemStruct);
    let impls = models::model(&mut ast);
    let mut tokens = ast.to_token_stream();
    tokens.extend(impls);
    TokenStream::from(tokens)
}

#[proc_macro_attribute]
pub fn model_type(_: TokenStream, item: TokenStream) -> TokenStream {
    let mut ast = parse_macro_input!(item as syn::Item);
    let impls = models::model_type(&mut ast);
    let mut tokens = ast.to_token_stream();
    tokens.extend(impls);
    TokenStream::from(tokens)
}