1extern crate self as ft_derive;
2
3#[proc_macro_attribute]
4pub fn processor(
5 _attr: proc_macro::TokenStream,
6 item: proc_macro::TokenStream,
7) -> proc_macro::TokenStream {
8 handle(item, "processor", "handler")
9}
10
11#[proc_macro_attribute]
12pub fn wrapped_processor(
13 _attr: proc_macro::TokenStream,
14 item: proc_macro::TokenStream,
15) -> proc_macro::TokenStream {
16 handle(item, "processor", "wrapped_processor")
17}
18
19#[proc_macro_attribute]
20pub fn data(
21 _attr: proc_macro::TokenStream,
22 item: proc_macro::TokenStream,
23) -> proc_macro::TokenStream {
24 handle(item, "data", "handler")
25}
26
27#[proc_macro_attribute]
28pub fn form(
29 _attr: proc_macro::TokenStream,
30 item: proc_macro::TokenStream,
31) -> proc_macro::TokenStream {
32 handle(item, "form", "handler")
33}
34
35fn handle(item: proc_macro::TokenStream, kind: &str, handler: &str) -> proc_macro::TokenStream {
36 let syn::ItemFn {
37 attrs,
38 vis,
39 sig,
40 block,
41 } = syn::parse_macro_input!(item as syn::ItemFn);
42
43 let fn_name = &sig.ident;
44 let fn_name_entrypoint =
45 syn::Ident::new(format!("{}__entrypoint", fn_name).as_str(), fn_name.span());
46 let return_type: syn::Type =
47 syn::parse_str(format!("ft_sdk::{kind}::Result").as_str()).unwrap();
48 let handler: syn::Path =
49 syn::parse_str(format!("ft_sdk::from_request::{handler}::handle").as_str()).unwrap();
50
51 match sig.output {
52 syn::ReturnType::Default => {
53 return compiler_error(
54 format!("The return type must be ft_sdk::{kind}::Result").as_str(),
55 );
56 }
57 syn::ReturnType::Type(_, ref ty) => {
58 if ty.as_ref() != &return_type {
59 return compiler_error(
60 format!(
61 "The return type must be ft_sdk::{kind}::Result, not {}.",
62 proc_macro::TokenStream::from(quote::quote! { #ty })
63 )
64 .as_str(),
65 );
66 }
67 }
68 };
69
70 let expanded = quote::quote! {
71 #[unsafe(no_mangle)]
72 pub extern "C" fn #fn_name_entrypoint() {
73 #handler(#fn_name)
74 }
75
76 #(#attrs)*
77 #vis #sig {
78 #block
79 }
80 };
81
82 proc_macro::TokenStream::from(expanded)
84}
85
86fn compiler_error(msg: &str) -> proc_macro::TokenStream {
87 proc_macro::TokenStream::from(quote::quote! {
88 compile_error!(#msg);
89 })
90}