channel_server_derive/
lib.rs

1mod utils;
2
3use proc_macro::TokenStream;
4use quote::{format_ident, quote};
5use syn::{parse_macro_input, AttributeArgs, FnArg, ItemFn, Member, Meta, NestedMeta, Result};
6
7/// Wrap an function as an `Endpoint`.
8///
9/// # Example
10///
11/// ```ignore
12/// #[handler]
13/// fn example() {
14/// }
15/// ```
16#[proc_macro_attribute]
17pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
18    let args: AttributeArgs = parse_macro_input!(args as AttributeArgs);
19    let mut internal = false;
20
21    for arg in args {
22        if matches!(arg,NestedMeta::Meta(Meta::Path(p)) if p.is_ident("internal")) {
23            internal = true;
24        }
25    }
26
27    match generate_handler(internal, input) {
28        Ok(stream) => stream,
29        Err(err) => err.into_compile_error().into(),
30    }
31}
32
33fn generate_handler(internal: bool, input: TokenStream) -> Result<TokenStream> {
34    let crate_name = utils::get_crate_name(internal);
35    let item_fn = syn::parse::<ItemFn>(input)?;
36    let vis = &item_fn.vis;
37    let docs = item_fn
38        .attrs
39        .iter()
40        .filter(|attr| attr.path.is_ident("doc"))
41        .cloned()
42        .collect::<Vec<_>>();
43    let ident = &item_fn.sig.ident;
44    let call_await = if item_fn.sig.asyncness.is_some() {
45        Some(quote::quote!(.await))
46    } else {
47        None
48    };
49
50    let mut extractors = Vec::new();
51    let mut args = Vec::new();
52    for (idx, input) in item_fn.sig.inputs.clone().into_iter().enumerate() {
53        if let FnArg::Typed(pat) = input {
54            let ty = &pat.ty;
55            let id = quote::format_ident!("p{}", idx);
56            args.push(id.clone());
57            extractors.push(quote! {
58                let #id = <#ty as #crate_name::FromRequest>::from_request(&req, &mut body)?;
59            });
60        }
61    }
62
63    let expanded = quote! {
64        #(#docs)*
65        #[allow(non_camel_case_types)]
66        #vis struct #ident;
67
68        impl #crate_name::Endpoint for #ident {
69            type Output = #crate_name::Response;
70
71            #[allow(unused_mut)]
72            fn call(&self, mut req: #crate_name::Request) -> Result<Self::Output, #crate_name::ChannelError> {
73                let (req, mut body) = req.split();
74                #(#extractors)*
75                #item_fn
76                let res = #ident(#(#args),*)#call_await;
77                Ok(res.into_response())
78            }
79        }
80    };
81
82    Ok(expanded.into())
83}
84
85#[doc(hidden)]
86#[proc_macro]
87pub fn generate_implement_middlewares(_: TokenStream) -> TokenStream {
88    let mut impls = Vec::new();
89
90    for i in 2..=16 {
91        let idents = (0..i)
92            .map(|i| format_ident!("T{}", i + 1))
93            .collect::<Vec<_>>();
94        let output_type = idents.last().unwrap();
95        let first_ident = idents.first().unwrap();
96        let mut where_clauses = vec![quote! { #first_ident: Middleware<E> }];
97        let mut transforms = Vec::new();
98
99        for k in 1..i {
100            let prev_ident = &idents[k - 1];
101            let current_ident = &idents[k];
102            where_clauses.push(quote! { #current_ident: Middleware<#prev_ident::Output> });
103        }
104
105        for k in 0..i {
106            let n = Member::from(k);
107            transforms.push(quote! { let ep = self.#n.transform(ep); });
108        }
109
110        let expanded = quote! {
111            impl<E, #(#idents),*> Middleware<E> for (#(#idents),*)
112                where
113                    E: Endpoint,
114                    #(#where_clauses,)*
115            {
116                type Output = #output_type::Output;
117
118                fn transform(&self, ep: E) -> Self::Output {
119                    #(#transforms)*
120                    ep
121                }
122            }
123        };
124
125        impls.push(expanded);
126    }
127
128    quote!(#(#impls)*).into()
129}