checked_rs_macro_impl/
params.rs1use convert_case::{Case, Casing};
2use proc_macro2::TokenStream;
3use quote::{format_ident, ToTokens};
4use syn::spanned::Spanned;
5
6pub mod as_soft_or_hard;
7pub mod behavior_arg;
8pub mod derived_traits;
9pub mod lower_or_min;
10pub mod min_or_max;
11pub mod number_arg;
12pub mod number_arg_range;
13pub mod number_kind;
14pub mod number_value;
15pub mod number_value_range;
16pub mod panic_or_panicking;
17pub mod saturate_or_saturating;
18pub mod semi_or_colon;
19pub mod upper_or_max;
20
21pub use as_soft_or_hard::*;
22pub use behavior_arg::*;
23pub use derived_traits::*;
24pub use lower_or_min::*;
25pub use min_or_max::*;
26pub use number_arg::*;
27pub use number_arg_range::*;
28pub use number_kind::*;
29pub use number_value::*;
30pub use number_value_range::*;
31pub use panic_or_panicking::*;
32pub use saturate_or_saturating::*;
33pub use semi_or_colon::*;
34pub use upper_or_max::*;
35
36pub mod kw {
38 syn::custom_keyword!(derive);
39 syn::custom_keyword!(default);
40 syn::custom_keyword!(behavior);
41 syn::custom_keyword!(lower);
42 syn::custom_keyword!(upper);
43 syn::custom_keyword!(min);
44 syn::custom_keyword!(max);
45 syn::custom_keyword!(Soft);
46 syn::custom_keyword!(Hard);
47 syn::custom_keyword!(Saturate);
48 syn::custom_keyword!(Saturating);
49 syn::custom_keyword!(Panic);
50 syn::custom_keyword!(Panicking);
51 syn::custom_keyword!(MIN);
52 syn::custom_keyword!(MAX);
53}
54
55#[derive(Clone)]
56pub struct Params {
57 pub integer: NumberKind,
58 pub derived_traits: Option<DerivedTraits>,
59 pub vis: syn::Visibility,
60 pub ident: syn::Ident,
61 pub as_soft_or_hard: Option<AsSoftOrHard>,
62 pub behavior: BehaviorArg,
63 pub default_val: Option<NumberValue>,
64 pub lower_limit_val: NumberValue,
65 pub upper_limit_val: NumberValue,
66 pub full_coverage: bool,
67 pub exact_values: Option<Vec<NumberValue>>,
68 pub valid_ranges: Option<Vec<NumberValueRange>>,
69}
70
71impl std::fmt::Debug for Params {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 f.debug_struct("Params")
74 .field("integer", &self.integer)
75 .field("derived_traits", &self.derived_traits)
76 .field("vis", &self.vis.to_token_stream().to_string())
77 .field("ident", &self.ident)
78 .field("as_soft_or_hard", &self.as_soft_or_hard)
79 .field("behavior", &self.behavior)
80 .field("default_val", &self.default_val)
81 .field("lower_limit", &self.lower_limit_val)
82 .field("upper_limit", &self.upper_limit_val)
83 .field("full_coverage", &self.full_coverage)
84 .field("exact_values", &self.exact_values)
85 .field("valid_ranges", &self.valid_ranges)
86 .finish()
87 }
88}
89
90impl Params {
91 pub fn mod_ident(&self) -> syn::Ident {
92 format_ident!("clamped_{}", self.ident.to_string().to_case(Case::Snake))
93 }
94
95 pub fn guard_ident(&self) -> syn::Ident {
96 format_ident!("{}Guard", &self.ident)
97 }
98
99 pub fn value_ident(&self) -> syn::Ident {
100 format_ident!("{}Value", &self.ident)
101 }
102
103 pub fn other_ident(&self, other_name: &syn::Ident) -> syn::Ident {
104 format_ident!("{}{}", other_name, self.value_ident())
105 }
106
107 pub fn default_val_token(&self) -> TokenStream {
108 let kind = self.integer;
109
110 if let Some(val) = self.default_val {
112 return val.to_token_stream();
113 }
114
115 let zero = NumberValue::new(kind, 0);
116
117 if let Some(exacts) = &self.exact_values {
119 if exacts.contains(&zero) {
120 return zero.to_token_stream();
121 }
122 }
123
124 if let Some(ranges) = &self.valid_ranges {
125 for range in ranges {
126 if range.contains(&zero) {
127 return zero.to_token_stream();
128 }
129 }
130 }
131
132 self.lower_limit_token()
134 }
135
136 pub fn lower_limit_token(&self) -> TokenStream {
138 syn::parse_str(&self.lower_limit_val.to_string()).unwrap()
139 }
140
141 pub fn upper_limit_token(&self) -> TokenStream {
143 syn::parse_str(&self.upper_limit_val.to_string()).unwrap()
144 }
145
146 pub fn first_uniq_val(&self) -> NumberValue {
147 let exact_min = if let Some(exacts) = &self.exact_values {
148 exacts.first().copied()
149 } else {
150 None
151 };
152
153 let range_min = if let Some(ranges) = &self.valid_ranges {
154 ranges.first().map(|range| range.first_val())
155 } else {
156 None
157 };
158
159 match (exact_min, range_min) {
160 (Some(exact), Some(range)) => {
161 if exact < range {
162 exact
163 } else {
164 range
165 }
166 }
167 (Some(exact), None) => exact,
168 (None, Some(range)) => range,
169 (None, None) => self.lower_limit_val,
170 }
171 }
172
173 pub fn last_uniq_val(&self) -> NumberValue {
174 let exact_max = if let Some(exacts) = &self.exact_values {
175 exacts.last().copied()
176 } else {
177 None
178 };
179
180 let range_max = if let Some(ranges) = &self.valid_ranges {
181 ranges.last().map(|range| range.last_val())
182 } else {
183 None
184 };
185
186 match (exact_max, range_max) {
187 (Some(exact), Some(range)) => {
188 if exact > range {
189 exact
190 } else {
191 range
192 }
193 }
194 (Some(exact), None) => exact,
195 (None, Some(range)) => range,
196 (None, None) => self.upper_limit_val,
197 }
198 }
199
200 pub fn check_if_out_of_bounds<T: Spanned + ToTokens>(
202 &self,
203 ast: &T,
204 value: NumberValue,
205 ) -> syn::Result<()> {
206 let lower = self.lower_limit_val;
207 let upper = self.upper_limit_val;
208
209 if value < lower {
210 return Err(syn::Error::new(
211 ast.span(),
212 format!(
213 "{:?} value: {} is less than lower limit: {}",
214 self.integer, value, lower
215 ),
216 ));
217 }
218
219 if value > upper {
220 return Err(syn::Error::new(
221 ast.span(),
222 format!(
223 "{:?} value: {} is greater than upper limit: {}",
224 self.integer, value, upper
225 ),
226 ));
227 }
228
229 Ok(())
230 }
231
232 pub fn is_signed(&self) -> bool {
233 matches!(
234 self.integer,
235 NumberKind::I8
236 | NumberKind::I16
237 | NumberKind::I32
238 | NumberKind::I64
239 | NumberKind::I128
240 | NumberKind::ISize
241 )
242 }
243
244 pub fn is_u16_or_smaller(&self) -> bool {
246 matches!(self.integer, NumberKind::U8 | NumberKind::U16)
247 }
248
249 pub fn is_u16_or_larger(&self) -> bool {
251 matches!(
252 self.integer,
253 NumberKind::U16 | NumberKind::U32 | NumberKind::U64 | NumberKind::U128
254 )
255 }
256
257 pub fn is_u32_or_smaller(&self) -> bool {
259 matches!(
260 self.integer,
261 NumberKind::U8 | NumberKind::U16 | NumberKind::U32 | NumberKind::USize
262 )
263 }
264
265 pub fn is_u32_or_larger(&self) -> bool {
267 matches!(
268 self.integer,
269 NumberKind::U32 | NumberKind::USize | NumberKind::U64 | NumberKind::U128
270 )
271 }
272
273 pub fn is_u64_or_smaller(&self) -> bool {
275 matches!(
276 self.integer,
277 NumberKind::U8
278 | NumberKind::U16
279 | NumberKind::U32
280 | NumberKind::USize
281 | NumberKind::U64
282 )
283 }
284
285 pub fn is_u64_or_larger(&self) -> bool {
287 matches!(self.integer, NumberKind::U64 | NumberKind::U128)
288 }
289
290 pub fn is_usize_or_smaller(&self) -> bool {
291 matches!(
292 self.integer,
293 NumberKind::U8 | NumberKind::U16 | NumberKind::U32 | NumberKind::USize
294 )
295 }
296
297 pub fn is_usize_or_larger(&self) -> bool {
298 matches!(
299 self.integer,
300 NumberKind::USize | NumberKind::U64 | NumberKind::U128
301 )
302 }
303
304 pub fn is_u128_or_smaller(&self) -> bool {
306 matches!(
307 self.integer,
308 NumberKind::U8
309 | NumberKind::U16
310 | NumberKind::U32
311 | NumberKind::U64
312 | NumberKind::USize
313 | NumberKind::U128
314 )
315 }
316
317 pub fn is_i16_or_smaller(&self) -> bool {
318 matches!(
319 self.integer,
320 NumberKind::I8 | NumberKind::I16 | NumberKind::U8
321 )
322 }
323
324 pub fn is_i16_or_larger(&self) -> bool {
325 matches!(
326 self.integer,
327 NumberKind::I16 | NumberKind::I32 | NumberKind::I64 | NumberKind::I128
328 )
329 }
330
331 pub fn is_i32_or_smaller(&self) -> bool {
332 matches!(
333 self.integer,
334 NumberKind::I8
335 | NumberKind::I16
336 | NumberKind::I32
337 | NumberKind::ISize
338 | NumberKind::U8
339 | NumberKind::U16
340 )
341 }
342
343 pub fn is_i32_or_larger(&self) -> bool {
344 matches!(
345 self.integer,
346 NumberKind::I32 | NumberKind::I64 | NumberKind::ISize | NumberKind::I128
347 )
348 }
349
350 pub fn is_i64_or_smaller(&self) -> bool {
351 matches!(
352 self.integer,
353 NumberKind::I8
354 | NumberKind::I16
355 | NumberKind::I32
356 | NumberKind::ISize
357 | NumberKind::I64
358 | NumberKind::U8
359 | NumberKind::U16
360 | NumberKind::U32
361 )
362 }
363
364 pub fn is_i64_or_larger(&self) -> bool {
365 matches!(self.integer, NumberKind::I64 | NumberKind::I128)
366 }
367
368 pub fn is_isize_or_smaller(&self) -> bool {
369 matches!(
370 self.integer,
371 NumberKind::I8 | NumberKind::I16 | NumberKind::I32 | NumberKind::ISize | NumberKind::U8
372 )
373 }
374
375 pub fn is_isize_or_larger(&self) -> bool {
376 matches!(
377 self.integer,
378 NumberKind::ISize | NumberKind::I64 | NumberKind::I128
379 )
380 }
381
382 pub fn is_i128_or_smaller(&self) -> bool {
383 matches!(
384 self.integer,
385 NumberKind::I8
386 | NumberKind::I16
387 | NumberKind::I32
388 | NumberKind::I64
389 | NumberKind::I128
390 | NumberKind::U8
391 | NumberKind::U16
392 | NumberKind::U32
393 | NumberKind::U64
394 | NumberKind::USize
395 )
396 }
397}