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