1#[macro_use]
3extern crate quote;
4extern crate proc_macro;
5
6use proc_macro::TokenStream;
7use quote::{format_ident, ToTokens};
8use syn::{parse_macro_input, Data, DeriveInput, ItemEnum, ItemStruct};
9
10#[proc_macro_derive(FromPostgres)]
12pub fn derive_from_postgres(item: TokenStream) -> TokenStream {
13 let input = parse_macro_input!(item as ItemStruct);
14 let struct_name = input.ident;
15
16 let from_postgres_fields = input
17 .fields
18 .iter()
19 .map(|field| {
20 let field_name = field.ident.as_ref().unwrap();
21 let field_name_string = field.ident.as_ref().unwrap().to_string();
22 quote! {
23 #field_name: row.get(#field_name_string)
24 }
25 })
26 .collect::<Vec<_>>();
27
28 let try_from_postgres_fields = input.fields.iter().map(|field| {
29 let field_name = field.ident.as_ref().unwrap();
30 let field_name_string = field.ident.as_ref().unwrap().to_string();
31 quote! {
32 #field_name: row.try_get(#field_name_string).map_err(|_| tusk_rs::FromPostgresError::MissingColumn(#field_name_string))?
33 }
34 }).collect::<Vec<_>>();
35
36 quote! {
37 impl tusk_rs::FromPostgres for #struct_name {
38 fn from_postgres(row: &tusk_rs::Row) -> #struct_name {
39 #struct_name {
40 #(#from_postgres_fields),*
41 }
42 }
43 fn try_from_postgres(row: &tusk_rs::Row) -> Result<#struct_name, tusk_rs::FromPostgresError> {
44 Ok(#struct_name {
45 #(#try_from_postgres_fields),*
46 })
47 }
48 }
49 }.into()
50}
51
52#[proc_macro_derive(PostgresJoins)]
54pub fn derive_postgres_joins(item: TokenStream) -> TokenStream {
55 let input = parse_macro_input!(item as ItemStruct);
56 let struct_name = input.ident;
57
58 quote! {
59 impl tusk_rs::PostgresJoins for #struct_name {
60 fn joins() -> &'static [&'static tusk_rs::PostgresJoin] {
61 &[]
62 }
63 }
64 }
65 .into()
66}
67
68#[proc_macro_derive(PostgresReadFields)]
70pub fn derive_postgres_read_fields(item: TokenStream) -> TokenStream {
71 let input = parse_macro_input!(item as ItemStruct);
72 let struct_name = input.ident;
73
74 let fields = input
75 .fields
76 .iter()
77 .map(|field| {
78 let field_name = field.ident.as_ref().unwrap().to_string();
79 quote! {
80 tusk_rs::local!(#field_name)
81 }
82 })
83 .collect::<Vec<_>>();
84
85 quote! {
86 impl tusk_rs::PostgresReadFields for #struct_name {
87 fn read_fields() -> &'static [&'static tusk_rs::PostgresField] {
88 &[#(#fields),*]
89 }
90 }
91 }
92 .into()
93}
94
95#[proc_macro_derive(PostgresReadable)]
97pub fn derive_postgres_readable(item: TokenStream) -> TokenStream {
98 let input = parse_macro_input!(item as ItemStruct);
99 let struct_name = input.ident;
100
101 quote! {
102 impl tusk_rs::PostgresReadable for #struct_name {}
103 }
104 .into()
105}
106
107#[proc_macro_derive(PostgresWriteFields)]
109pub fn derive_postgres_write_fields(item: TokenStream) -> TokenStream {
110 let input = parse_macro_input!(item as ItemStruct);
111 let struct_name = input.ident;
112
113 let fields = input
114 .fields
115 .iter()
116 .map(|field| field.ident.as_ref().unwrap().to_string())
117 .collect::<Vec<_>>();
118
119 quote! {
120 impl tusk_rs::PostgresWriteFields for #struct_name {
121 fn write_fields() -> &'static [&'static str] {
122 &[#(#fields),*]
123 }
124 }
125 }
126 .into()
127}
128#[proc_macro_derive(PostgresWriteable)]
130pub fn derive_postgres_writeable(item: TokenStream) -> TokenStream {
131 let input = parse_macro_input!(item as ItemStruct);
132 let struct_name = input.ident;
133
134 let fields = input
135 .fields
136 .iter()
137 .map(|field| {
138 let f = field.ident.as_ref().unwrap();
139 let f_name = field.ident.as_ref().unwrap().to_string();
140 quote! {
141 #f_name => Box::new(self.#f.clone())
142 }
143 })
144 .collect::<Vec<_>>();
145
146 quote! {
147 impl tusk_rs::PostgresWriteable for #struct_name {
148 fn write(mut self) -> tusk_rs::PostgresWrite {
149 let mut arguments: Vec<Box<(dyn tusk_rs::ToSql + Sync)>> = vec![];
150 let fields = <Self as tusk_rs::PostgresWriteFields>::write_fields();
151 for f in fields {
152 arguments.push(
153 match *f {
154 #(#fields),*,
155 _ => panic!("Unknown field {}!", f)
156 }
157 )
158 }
159 tusk_rs::PostgresWrite {
160 fields,
161 arguments
162 }
163 }
164 }
165 }
166 .into()
167}
168
169#[proc_macro]
176pub fn embed(item: TokenStream) -> TokenStream {
177 let path = item.to_string().replace('\"', "");
178 let resolved_path = std::fs::canonicalize(path).expect("Invalid path!");
179 let contents = std::fs::read(&resolved_path)
180 .unwrap_or_else(|_| panic!("Could not read contents at {}", resolved_path.display()));
181 let contents_string = String::from_utf8(contents).unwrap();
182 quote! {
183 #contents_string
184 }
185 .into()
186}
187
188#[proc_macro]
196pub fn embed_binary(item: TokenStream) -> TokenStream {
197 let path = item.to_string().replace('\"', "");
198 let resolved_path = std::fs::canonicalize(path).expect("Invalid path!");
199 let contents = std::fs::read(&resolved_path)
200 .unwrap_or_else(|_| panic!("Could not read contents at {}", resolved_path.display()));
201 quote! {
202 &[#(#contents),*]
203 }
204 .into()
205}
206
207#[proc_macro_derive(ToJson)]
209pub fn derive_to_json(item: TokenStream) -> TokenStream {
210 let input = parse_macro_input!(item as DeriveInput);
211 match input.data {
212 Data::Struct(struct_ident) => {
213 let struct_name = input.ident;
214 let struct_fields = struct_ident.fields.iter().map(|x| {
215 let x_ident = &x.ident;
216 let x_key = x.ident.to_token_stream().to_string();
217 quote! {
218 output += "\"";
219 output += #x_key;
220 output += "\" : ";
221 output += &self.#x_ident.to_json();
222 output += ",";
223 }
224 });
225 let generics = input.generics;
226 let impl_types = generics
227 .params
228 .iter()
229 .map(|x| {
230 let d = format_ident!(
231 "{}",
232 x.to_token_stream()
233 .to_string()
234 .split(':')
235 .next()
236 .unwrap()
237 .trim()
238 );
239 quote! {#d}
240 })
241 .collect::<Vec<_>>();
242 let impl_insert = if impl_types.is_empty() {
243 quote! {}
244 } else {
245 quote! {<#(#impl_types),*>}
246 };
247
248 let output_new = quote! {
249 impl #generics tusk_rs::ToJson for #struct_name #impl_insert {
250 fn to_json(&self) -> String {
251 let mut output = String::new();
252 output += "{";
253 #(#struct_fields)*
254 output.pop();
255 output += "}";
256 return output;
257 }
258 }
259 };
260
261 output_new.into()
262 }
263 Data::Enum(enum_ident) => {
264 let name = &input.ident;
265 let opts = enum_ident
266 .variants
267 .iter()
268 .map(|x| {
269 let ident = &x.ident;
270 let ident_str = format!("\"{}\"", x.ident);
271 quote! {
272 Self::#ident => #ident_str.to_string()
273 }
274 })
275 .collect::<Vec<_>>();
276 quote! {
277 impl tusk_rs::ToJson for #name {
278 fn to_json(&self) -> String {
279 match self {
280 #(#opts),*
281 }
282 }
283 }
284 }
285 .into()
286 }
287 _ => panic!("Cannot derive for this kind!"),
288 }
289}
290
291#[proc_macro_derive(JsonRetrieve)]
294pub fn derive_json_retrieve(item: TokenStream) -> TokenStream {
295 let enm = parse_macro_input!(item as ItemEnum);
296 let struct_name = &enm.ident;
297 let struct_name_str = enm.ident.to_string();
298
299 let fields_map = enm
300 .variants
301 .iter()
302 .map(|x| {
303 let name = &x.ident;
304 let str = format!("\"{}\"", x.ident.to_token_stream());
305 quote! {
306 #str => Ok(Self::#name)
307 }
308 })
309 .collect::<Vec<_>>();
310
311 quote! {
312 impl tusk_rs::JsonRetrieve for #struct_name {
313 fn parse(key: String, value: Option<&String>) -> Result<Self, tusk_rs::JsonParseError> {
314 let value = value.ok_or_else(|| tusk_rs::JsonParseError::NotFound(key.clone()))?;
315 match value.as_str() {
316 #(#fields_map),*,
317 _ => return Err(tusk_rs::JsonParseError::InvalidType(key, #struct_name_str))
318 }
319 }
320 }
321 }
322 .into()
323}
324
325#[proc_macro_derive(FromJson)]
327pub fn derive_from_json(item: TokenStream) -> TokenStream {
328 let strct = parse_macro_input!(item as ItemStruct);
329 let struct_name = &strct.ident;
330
331 let fields_get = strct.fields.iter().map(|x| {
332 let x_ident = &x.ident;
333 let x_key = x.ident.to_token_stream().to_string();
334 quote! {
335 #x_ident: json.get(#x_key)?
336 }
337 });
338
339 quote! {
340 impl tusk_rs::FromJson for #struct_name {
341 fn from_json(json: &tusk_rs::JsonObject) -> Result<#struct_name, tusk_rs::JsonParseError> {
342 Ok(#struct_name {
343 #(#fields_get),*
344 })
345 }
346 }
347 }.into()
348}