1use proc_macro_crate::{crate_name, FoundCrate};
2use quote::quote;
3use syn::{parse::Parse, parse_macro_input, Expr};
4
5struct Input {
6 value: Expr,
7 suffix_unit: String,
8}
9
10impl Parse for Input {
11 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
12 let value = input.parse::<Expr>()?;
13
14 let rest: proc_macro2::TokenStream = input.parse()?;
15 let mut suffix_unit = String::new();
16 for tt in rest {
17 suffix_unit.push_str(&tt.to_string());
18 }
19
20 Ok(Input { value, suffix_unit })
21 }
22}
23
24#[proc_macro]
25pub fn u(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
26 let input = parse_macro_input!(input as Input);
27
28 for (unit_name, unit) in UNITS_MAP {
29 if input.suffix_unit.ends_with(unit_name) {
30 let suffix_len = input.suffix_unit.len() - unit_name.len();
31 let cpath = get_crate_path();
32 let value = input.value.clone();
33 let unit_ident = syn::Ident::new(unit, proc_macro2::Span::call_site());
34
35 let input_suffix = &input.suffix_unit[..suffix_len];
36 for &(suffix_name, suffix) in SUFFIX_MAP.iter() {
37 if suffix_name == input_suffix {
38 let suffix = syn::Ident::new(suffix, proc_macro2::Span::call_site());
39 let code = quote! {
40 #cpath::#unit_ident::new(#cpath::Number::new(#value as f64, #cpath::Suffix::#suffix))
41 };
42
43 return code.into();
44 }
45 }
46
47 return syn::Error::new_spanned(quote! { #input_suffix }, "Invalid suffix")
48 .to_compile_error()
49 .into();
50 }
51 }
52
53 let suffix_unit = input.suffix_unit;
54 syn::Error::new_spanned(quote! { #suffix_unit }, "Invalid suffix+unit")
55 .to_compile_error()
56 .into()
57}
58
59fn get_crate_path() -> proc_macro2::TokenStream {
60 match crate_name("reda-unit") {
61 Ok(FoundCrate::Itself) => {
62 quote! { crate }
63 }
64 Ok(FoundCrate::Name(name)) => {
65 let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
66 quote! { #ident }
67 }
68 Err(_) => {
69 quote! { reda-unit }
70 }
71 }
72}
73
74const SUFFIX_MAP: &[(&str, &str)] = &[
75 ("m", "Milli"),
76 ("k", "Kilo"),
77 ("K", "Kilo"),
78 ("M", "Mega"),
79 ("G", "Giga"),
80 ("u", "Micro"),
81 ("n", "Nano"),
82 ("p", "Pico"),
83 ("", "None"),
84];
85
86const UNITS_MAP: &[(&str, &str)] = &[
87 ("m", "Length"),
88 ("m²", "Area"),
89 ("N", "Force"),
90 ("Pa", "Pressure"),
91 ("Wb", "MagneticFlux"),
92 ("T", "FluxDensity"),
93 ("S", "Conductance"),
94 ("m/s", "Velocity"),
95 ("m/s²", "Accel"),
96 ("K", "Temperature"),
97 ("rad", "Angle"),
98 ("V", "Voltage"),
99 ("v", "Voltage"),
100 ("A", "Current"),
101 ("Ω", "Resistance"),
102 ("F", "Capacitance"),
103 ("H", "Inductance"),
104 ("Q", "Charge"),
105 ("W", "Power"),
106 ("J", "Energy"),
107 ("s", "Time"),
108 ("Hz", "Frequency"),
109 ("HZ", "Frequency"),
110 ("hz", "Frequency"),
111];