osom_lib_primitives_proc_macros/
lib.rs1#![deny(warnings)]
3#![allow(unused_features)]
4#![doc(hidden)]
5#![warn(clippy::all, clippy::pedantic)]
6
7use quote::quote;
8
9#[proc_macro]
13pub fn try_unpack(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
14 let expression = match syn::parse::<syn::Expr>(tokens) {
15 Ok(ok) => ok,
16 Err(err) => {
17 return err.into_compile_error().into();
18 }
19 };
20
21 quote! {
22 {
23 use ::osom_lib_primitives::cresult::CResult;
24
25 match { #expression } {
26 CResult::Ok(ok) => ok,
27 CResult::Err(err) => {
28 return CResult::Err(err);
29 }
30 }
31 }
32 }
33 .into()
34}
35
36#[proc_macro]
41pub fn make_length(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
42 let expression = match syn::parse::<syn::Expr>(tokens) {
43 Ok(ok) => ok,
44 Err(err) => {
45 return err.into_compile_error().into();
46 }
47 };
48
49 let org_expr = unpack_brackets(&expression);
50 let (sign, expr) = unpack_negative_sign(org_expr);
51
52 match expr {
53 syn::Expr::Lit(expr_lit) => match &expr_lit.lit {
54 syn::Lit::Int(lit_int) => {
55 let Ok(value) = lit_int.base10_parse::<u32>() else {
56 return quote! {
57 compile_error!("Invalid literal integer.");
58 }
59 .into();
60 };
61
62 if sign < 0 {
63 return quote! {
64 compile_error!("Length has to be non-negative.");
65 }
66 .into();
67 }
68
69 if value == 0 {
70 return quote! {
71 ::osom_lib_primitives::length::Length::ZERO
72 }
73 .into();
74 }
75
76 if value == 1 {
77 return quote! {
78 ::osom_lib_primitives::length::Length::ONE
79 }
80 .into();
81 }
82
83 quote! {
84 {
85 const {
86 match ::osom_lib_primitives::length::Length::try_from_u32(#value) {
87 Ok(val) => val,
88 Err(_) => panic!("The literal value is above Length::MAX_LENGTH."),
89 }
90 }
91 }
92 }
93 .into()
94 }
95 _ => quote! {
96 compile_error!("Expected literal integer.");
97 }
98 .into(),
99 },
100 _ => quote! {
101 {
102 ::osom_lib_primitives::length::Length::try_from_u32(#org_expr).unwrap()
103 }
104 }
105 .into(),
106 }
107}
108
109#[proc_macro]
114pub fn make_offset(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
115 let expression = match syn::parse::<syn::Expr>(tokens) {
116 Ok(ok) => ok,
117 Err(err) => {
118 return err.into_compile_error().into();
119 }
120 };
121
122 let org_expr = unpack_brackets(&expression);
123 let (sign, expr) = unpack_negative_sign(org_expr);
124
125 match expr {
126 syn::Expr::Lit(expr_lit) => match &expr_lit.lit {
127 syn::Lit::Int(lit_int) => {
128 let Ok(value) = lit_int.base10_parse::<i32>() else {
129 return quote! {
130 compile_error!("Invalid literal integer.");
131 }
132 .into();
133 };
134
135 let real_value = value * sign;
136
137 if real_value == -1 {
138 return quote! {
139 ::osom_lib_primitives::offset::Offset::MINUS_ONE
140 }
141 .into();
142 }
143
144 if real_value == 0 {
145 return quote! {
146 ::osom_lib_primitives::offset::Offset::ZERO
147 }
148 .into();
149 }
150
151 if real_value == 1 {
152 return quote! {
153 ::osom_lib_primitives::offset::Offset::ONE
154 }
155 .into();
156 }
157
158 quote! {
159 {
160 const {
161 match ::osom_lib_primitives::offset::Offset::try_from_i32(#real_value) {
162 Ok(val) => val,
163 Err(_) => panic!("The literal value is out of [Offset::MIN_OFFSET..Offset::MAX_OFFSET] range."),
164 }
165 }
166 }
167 }.into()
168 }
169 _ => quote! {
170 compile_error!("Expected literal integer.");
171 }
172 .into(),
173 },
174 _ => quote! {
175 {
176 ::osom_lib_primitives::offset::Offset::try_from_i32(#org_expr).unwrap()
177 }
178 }
179 .into(),
180 }
181}
182
183fn unpack_brackets(expr: &syn::Expr) -> &syn::Expr {
184 match expr {
185 syn::Expr::Paren(expr_paren) => unpack_brackets(&expr_paren.expr),
186 expr => expr,
187 }
188}
189
190fn unpack_negative_sign(expr: &syn::Expr) -> (i32, &syn::Expr) {
191 match expr {
192 syn::Expr::Unary(expr_unary) => {
193 match expr_unary.op {
194 syn::UnOp::Neg(_) => {}
195 _ => {
196 panic!("Invalid unary expression, expected either positive or negative integer.");
197 }
198 }
199 (-1, &expr_unary.expr)
200 }
201 expr => (1, expr),
202 }
203}