1use quote::{quote, ToTokens};
2use syn::parse_macro_input;
3
4mod base;
5mod big_ops;
6mod by_number;
7mod checked_ops;
8mod factories;
9mod ops;
10mod others;
11mod structs;
12mod utils;
13
14use structs::DecimalCharacteristics;
15
16use utils::string_to_ident;
17
18#[proc_macro_attribute]
19pub fn decimal(
20 attr: proc_macro::TokenStream,
21 item: proc_macro::TokenStream,
22) -> proc_macro::TokenStream {
23 let args_str = attr.to_string();
24 let args: Vec<&str> = args_str.split(',').collect();
25
26 let parsed_scale = args[0].parse::<u8>().unwrap_or(0);
27
28 let big_type = match args.len() {
29 1 => string_to_ident("", "U256"),
30 2 => string_to_ident("", args[1].trim()),
31 _ => panic!("decimal: invalid number of parameters"),
32 };
33
34 assert!(parsed_scale <= 38, "scale too big");
35
36 let k = item.clone();
37 let decimal_struct = parse_macro_input!(k as syn::ItemStruct);
38
39 let fields = decimal_struct.fields;
40 let first_field = fields.iter().next().unwrap();
41
42 let underlying_type =
43 string_to_ident("", first_field.ty.to_token_stream().to_string().as_str());
44
45 let field_name = match first_field.ident.clone() {
46 Some(ident) => quote! {#ident},
47 None => quote! {0},
48 };
49
50 let struct_name = decimal_struct.ident;
51
52 let characteristics = DecimalCharacteristics {
53 struct_name: struct_name.clone(),
54 field_name: field_name.clone(),
55 underlying_type: underlying_type.clone(),
56 big_type: big_type.clone(),
57 scale: parsed_scale,
58 };
59
60 let mut result = proc_macro::TokenStream::from(quote! {
61 });
63
64 result.extend(item.clone());
65
66 result.extend(base::generate_base(characteristics.clone()));
67 result.extend(ops::generate_ops(characteristics.clone()));
68 result.extend(big_ops::generate_big_ops(characteristics.clone()));
69 result.extend(by_number::generate_by_number(characteristics.clone()));
70 result.extend(others::generate_others(characteristics.clone()));
71 result.extend(factories::generate_factories(characteristics.clone()));
72 result.extend(checked_ops::generate_checked_ops(characteristics.clone()));
73
74 result.extend(proc_macro::TokenStream::from(quote! {
75 impl #struct_name {
76 pub fn is_zero(self) -> bool {
77 self.#field_name == #underlying_type::try_from(0).unwrap()
78 }
79 }
80 }));
81
82 result
83}