tinyhttp_codegen/
lib.rs

1use std::ops::Deref;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::spanned::Spanned;
6
7#[proc_macro_attribute]
8pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
9    let item_fn: syn::ItemFn = syn::parse(item).unwrap();
10    let value: syn::LitStr = syn::parse(attr).unwrap();
11
12    let sig = item_fn.sig;
13    let name = sig.ident.clone();
14    let body = item_fn.block.deref();
15    let return_type = sig.output;
16
17    let fn_args = sig.inputs;
18    let is_body_args = !fn_args.is_empty();
19    //eprintln!("LEN: {}", body_args.len());
20
21    let mut path = value.value();
22    /*match path_token {
23        syn::NestedMeta::Meta(_) => panic!("IN TOKEN MATCH!"),
24        syn::NestedMeta::Lit(e) => match e {
25            syn::Lit::Str(e) => {
26                path = e.value();
27            }
28            syn::Lit::ByteStr(_) => panic!("IN TOKEN MATCH!"),
29            syn::Lit::Byte(_) => panic!("IN TOKEN MATCH!"),
30            syn::Lit::Char(_) => panic!("IN TOKEN MATCH!"),
31            syn::Lit::Int(_) => panic!("IN TOKEN MATCH!"),
32            syn::Lit::Float(_) => panic!("IN TOKEN MATCH!"),
33            syn::Lit::Bool(_) => panic!("IN TOKEN MATCH!"),
34            syn::Lit::Verbatim(_) => panic!("IN TOKEN MATCH!"),
35        },
36    };*/
37
38    let new_wildcard = if path.contains("/:") {
39        let path_clone = path.clone();
40        let mut iter = path_clone.split(':');
41        path = iter.next().unwrap().to_string();
42        let id = iter.next().unwrap().to_string();
43        if path.len() != 1 {
44            path.pop();
45        };
46        quote! {get_route = get_route.set_wildcard(#id.into());}
47    } else {
48        quote! {}
49    };
50
51    let span = return_type.span();
52    let return_error = match return_type {
53        syn::ReturnType::Default => Some(
54            syn::Error::new(span, "You're forgetting to return something...").into_compile_error(),
55        ),
56        _ => None,
57    };
58
59    if let Some(e) = return_error {
60        return e.into();
61    }
62
63    // let is_ret_type_res = return_type_str == "Response";
64
65    //    let new_get_body = if is_ret_type_res {
66    //        quote! {
67    //            let mut get_route = GetRouteWithReqAndRes::new()
68    //                .set_path(#path.into());
69    //
70    //            fn body(#body_args) -> Response {
71    //                #body.into()
72    //            }
73    //
74    //            get_route = get_route.set_body(body);
75    //        }
76    let new_get_body = if is_body_args {
77        let mut fn_args_iter = fn_args.iter();
78        let first_arg_name = fn_args_iter.next().unwrap();
79        let arg_type = match first_arg_name {
80            syn::FnArg::Typed(i) => i.to_owned(),
81            _ => todo!(),
82        };
83
84        quote! {
85            let mut get_route = GetRouteWithReqAndRes::new()
86                .set_path(#path.into());
87
88            fn body<'b>(try_from_req: &'b mut Request, _sock: &'b mut std::net::TcpStream) -> Response {
89                let #arg_type = try_from_req.into();
90                #body.into()
91            }
92
93            // OG
94            // fn body(#body_args) -> Response {
95            // #body.into()
96            // }
97
98            get_route = get_route.set_body(body);
99        }
100    } else {
101        quote! {
102            let mut get_route = BasicGetRoute::new()
103                .set_path(#path.into());
104
105            fn body() -> Response {
106                #body.into()
107            }
108
109            get_route = get_route.set_body(body);
110        }
111    };
112
113    let output = quote! {
114        fn #name() -> Box<dyn Route> {
115            /*let mut get_route = GetRoute::new()
116                .set_path(#path.into())
117                .set_is_args(#is_body_args)
118                .set_is_ret_res(#is_ret_type_res);*/
119
120
121            #new_get_body
122            #new_wildcard
123
124            Box::new(get_route)
125        }
126    };
127
128    output.into()
129}
130
131#[proc_macro_attribute]
132pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
133    //eprintln!("{:#?}\n{:#?}", attr, item);
134    let item: syn::ItemFn = syn::parse(item).unwrap();
135    let value: syn::LitStr = syn::parse(attr).unwrap();
136
137    let fn_args = item.sig.inputs;
138    let name = item.sig.ident.clone();
139    let body = item.block.deref();
140    let return_type = item.sig.output;
141
142    let is_body_args = !fn_args.is_empty();
143
144    let mut path = value.value();
145    let new_wildcard = if path.contains("/:") {
146        let path_clone = path.clone();
147        let mut iter = path_clone.split(':');
148        path = iter.next().unwrap().to_string();
149        let id = iter.next().unwrap().to_string();
150        if path.len() != 1 {
151            path.pop();
152        };
153        quote! {post_route = post_route.set_wildcard(#id.into());}
154    } else {
155        quote! {}
156    };
157
158    let return_error = match return_type {
159        syn::ReturnType::Default => Some(
160            syn::Error::new(
161                return_type.span(),
162                "You're forgetting to return something...",
163            )
164            .into_compile_error(),
165        ),
166        _ => None,
167    };
168
169    if let Some(e) = return_error {
170        return e.into();
171    }
172
173    let new_post_body = if is_body_args {
174        let first_arg_name = fn_args.first().unwrap();
175        let arg_type = match first_arg_name {
176            syn::FnArg::Typed(i) => i.to_owned(),
177            _ => todo!(),
178        };
179        // NOTE: Gets arg name and type
180        //        let arg_name_pat = match &arg_type.pat.deref() {
181        //            syn::Pat::Ident(i) => i.to_owned(),
182        //            _ => todo!(),
183        //        };
184        //        let arg_name_type = match &arg_type.ty.deref() {
185        //            syn::Type::Path(i) => i.to_owned(),
186        //            _ => todo!(),
187        //        };
188        //
189        //        let arg_name_type = &arg_name_type.path.segments.first().unwrap().ident;
190        quote! {
191
192            let mut post_route = PostRouteWithReqAndRes::new()
193                .set_path(#path.into());
194
195            fn body<'b>(try_from_req: &'b mut Request, _sock: &'b mut std::net::TcpStream) -> Response {
196                let #arg_type = try_from_req.into();
197                #body.into()
198            }
199
200            post_route = post_route.set_body(body);
201        }
202    } else {
203        quote! {
204            let mut post_route = BasicPostRoute::new()
205                .set_path(#path.into());
206
207            fn body() -> Response {
208                #body.into()
209            }
210
211            post_route = post_route.set_body(body);
212        }
213    };
214
215    let output = quote! {
216        fn #name() -> Box<dyn Route> {
217            /*let mut post_route = PostRoute::new()
218                .set_path(#path.into())
219                .set_is_args(#is_body_args)
220                .set_is_ret_res(#is_ret_type_res);*/
221
222            #new_post_body
223            #new_wildcard
224
225            Box::new(post_route)
226        }
227    };
228
229    /*let output = quote! {
230        fn #name() -> (String, Vec<u8>, Method) {
231            fn body() #output {
232                #body
233            }
234
235            (#path.into(), body().into(), Method::POST)
236        }
237    };*/
238
239    output.into()
240}