rest_client_codegen/
lib.rs1extern crate proc_macro;
2extern crate proc_macro2;
3
4use crate::proc_macro::TokenStream;
5use quote::quote;
6use syn;
7
8#[proc_macro_attribute]
9pub fn rest(attr: TokenStream, item: TokenStream) -> TokenStream {
10 let args = syn::parse_macro_input!(attr as syn::AttributeArgs);
11 if args.is_empty() {
12 panic!("invalid number of arguments");
13 }
14
15 let path = match args[0] {
17 syn::NestedMeta::Literal(syn::Lit::Str(ref fname)) => {
18 let fname = quote!(#fname).to_string();
19 fname.as_str()[1..fname.len() - 1].to_owned()
20 }
21 _ => panic!("resource path"),
22 };
23
24 let mut is_vec = false;
25 let mut wrapper: Option<syn::Ident> = None;
26 for arg in args[1..].iter() {
27 match arg {
28 syn::NestedMeta::Meta(syn::Meta::Word(ref fname))
29 if fname == &syn::Ident::new("vec", proc_macro2::Span::call_site()) =>
30 {
31 is_vec = true;
32 }
33 syn::NestedMeta::Meta(syn::Meta::NameValue(ref value))
34 if value.ident == syn::Ident::new("wrapper", proc_macro2::Span::call_site()) =>
35 {
36 let lit = if let syn::Lit::Str(name) = &value.lit {
37 name
38 } else {
39 panic!("wrapper has not the format wrapper = \"Type\"");
40 };
41 wrapper = Some(syn::Ident::new(&lit.value(), lit.span()));
42 }
43 _ => {}
44 }
45 }
46
47 let item_copy = item.clone();
48 let input = syn::parse_macro_input!(item_copy as syn::ItemStruct);
49 let item: proc_macro2::TokenStream = item.into();
50 let ident = &input.ident;
51
52 let mut result_type = if is_vec {
53 quote! { Vec<Self> }
54 } else {
55 quote! { Self }
56 };
57
58 if let Some(wrapper) = wrapper {
59 result_type = quote! { #wrapper<#result_type> };
60 };
61
62 let final_trait = quote! { ClientMethods<#result_type> };
63
64 let count = path.matches("{}").count();
65 let mut counter_vec = Vec::new();
66 for _i in 0..count {
67 counter_vec.push(quote! { iter.next().unwrap() });
68 }
69
70 let result = quote! {
71 impl #final_trait for #ident {
72 fn get(parameters: impl IntoIterator<Item = impl std::fmt::Display>) -> Result<#result_type, Box<std::error::Error>> {
73 let mut iter = parameters.into_iter();
74 let request_path = format!(#path, #(#counter_vec),*);
75 let new_self: #result_type = reqwest::get(&request_path)?
76 .json()?;
77 Ok(new_self)
78 }
79 }
80 };
81
82 (quote! {
83 #item
84 #result
85 })
86 .into()
87}