1extern crate proc_macro;
2use core::panic;
3
4use proc_macro::TokenStream;
5use quote::quote;
6use syn::{parse_macro_input, DeriveInput, Ident};
7
8#[proc_macro_attribute]
10pub fn rest_model(args: TokenStream, item: TokenStream) -> TokenStream {
11 let input = parse_macro_input!(item as DeriveInput);
13 let original = input.clone();
14 let struct_name = input.ident;
15
16 let mut get = false;
17 let mut get_with_id = false;
18 let mut put = false;
19 let mut patch = false;
20 let mut delete = false;
21
22 let mut db: Option<Ident> = None;
24 let mut db_name: Option<Ident> = None;
25 let mut table_name: Option<Ident> = None;
26 let parser = syn::meta::parser(|meta| {
27 if meta.path.is_ident("db") {
28 let mut i = 0;
29 meta.parse_nested_meta(|meta| {
30 let ident = meta.path.get_ident().unwrap();
31 if i == 0 {
32 db = Some(ident.clone());
33 } else if i == 1 {
34 db_name = Some(ident.clone());
35 } else if i == 2 {
36 table_name = Some(ident.clone());
37 } else {
38 return Err(meta.error("rest_model db only support 3 params"));
39 }
40 i += 1;
41 Ok(())
42 })?;
43 if i != 3 {
44 return Err(meta.error("rest_model db only support 3 params"));
45 }
46 Ok(())
47 } else if meta.path.is_ident("with") {
48 meta.parse_nested_meta(|meta| {
49 if meta.path.is_ident("get") {
50 get = true;
51 Ok(())
52 } else if meta.path.is_ident("get_with_id") {
53 get_with_id = true;
54 Ok(())
55 } else if meta.path.is_ident("put") {
56 put = true;
57 Ok(())
58 } else if meta.path.is_ident("patch") {
59 patch = true;
60 Ok(())
61 } else if meta.path.is_ident("delete") {
62 delete = true;
63 Ok(())
64 } else if meta.path.is_ident("all") {
65 get = true;
66 get_with_id = true;
67 put = true;
68 patch = true;
69 delete = true;
70 Ok(())
71 } else {
72 Err(meta.error("unsupported rest_model with property"))
73 }
74 })
75 } else {
76 Err(meta.error(format!(
77 "unsupported rest_model property `{}`",
78 meta.path.get_ident().unwrap().to_string()
79 )))
80 }
81 });
82
83 parse_macro_input!(args with parser);
84
85 if db.is_none() {
86 panic!("Db must be specified");
87 }
88
89 let mut methods = quote! {
91 impl rest_model::RestModel for #struct_name {
92 fn get_db_name() -> &'static str {
93 #db_name
94 }
95 fn get_table_name() -> &'static str {
96 #table_name
97 }
98 }
99 impl rest_model::method::Init<#struct_name, #db> for #struct_name {}
100 };
101 if get_with_id {
102 methods.extend(quote! {
103 impl rest_model::method::GetWithId<#struct_name, #db> for #struct_name {}
104 });
105 }
106 if get {
107 methods.extend(quote! {
108 impl rest_model::method::Get<#struct_name, #db> for #struct_name {}
109 });
110 }
111 if put {
112 methods.extend(quote! {
113 impl rest_model::method::Put<#struct_name, #db> for #struct_name {}
114 });
115 }
116 if patch {
117 methods.extend(quote! {
118 impl rest_model::method::Patch<#struct_name, #db> for #struct_name {}
119 });
120 }
121 if delete {
122 methods.extend(quote! {
123 impl rest_model::method::Delete<#struct_name, #db> for #struct_name {}
124 });
125 }
126
127 let expanded = quote! {
129 #original
130 #methods
131 };
132
133 TokenStream::from(expanded)
135}