qubit_common/lang/argument/numeric.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Numeric Argument Validation
10//!
11//! Provides validation functionality for numeric type arguments.
12//!
13//! # Author
14//!
15//! Haixing Hu
16
17use super::error::{
18 ArgumentError,
19 ArgumentResult,
20};
21use std::fmt::Display;
22
23/// Numeric argument validation trait
24///
25/// Provides validation methods for all sortable numeric types, supporting method chaining.
26///
27/// # Features
28///
29/// - Zero-cost abstraction: Same performance as manual checks after compilation
30/// - Method chaining: Can perform multiple validations in sequence
31/// - Type safety: Leverages Rust's type system to ensure correctness
32/// - Clear errors: Provides friendly error messages
33///
34/// # Use Cases
35///
36/// - Validating function parameter validity
37/// - Configuration value range checking
38/// - User input numeric validation
39///
40/// # Examples
41///
42/// Basic usage (returns `ArgumentResult`):
43///
44/// ```rust,ignore
45/// use qubit_common::lang::argument::{NumericArgument, ArgumentResult};
46///
47/// fn set_volume(volume: i32) -> ArgumentResult<()> {
48/// let volume = volume.require_in_closed_range("volume", 0, 100)?;
49/// println!("Volume: {}", volume);
50/// Ok(())
51/// }
52/// ```
53///
54/// Converting to other error types:
55///
56/// ```rust,ignore
57/// use qubit_common::lang::argument::NumericArgument;
58///
59/// fn set_volume(volume: i32) -> Result<(), String> {
60/// let volume = volume
61/// .require_non_negative("volume")
62/// .and_then(|v| v.require_in_closed_range("volume", 0, 100))
63/// .map_err(|e| e.to_string())?;
64/// println!("Volume: {}", volume);
65/// Ok(())
66/// }
67/// ```
68///
69/// # Author
70///
71/// Haixing Hu
72///
73pub trait NumericArgument: Sized {
74 /// Validate that value is zero
75 ///
76 /// # Parameters
77 ///
78 /// * `name` - Parameter name for error message generation
79 ///
80 /// # Returns
81 ///
82 /// Returns `Ok(self)` if value is zero, otherwise returns an error
83 ///
84 /// # Examples
85 ///
86 /// ```rust,ignore
87 /// use qubit_common::lang::argument::NumericArgument;
88 ///
89 /// let value: i32 = 0;
90 /// assert!(value.require_zero("value").is_ok());
91 ///
92 /// let non_zero: i32 = 5;
93 /// assert!(non_zero.require_zero("value").is_err());
94 /// ```
95 fn require_zero(self, name: &str) -> ArgumentResult<Self>;
96
97 /// Validate that value is non-zero
98 ///
99 /// # Parameters
100 ///
101 /// * `name` - Parameter name
102 ///
103 /// # Returns
104 ///
105 /// Returns `Ok(self)` if value is non-zero, otherwise returns an error
106 ///
107 /// # Examples
108 ///
109 /// ```rust,ignore
110 /// use qubit_common::lang::argument::NumericArgument;
111 ///
112 /// let value: i32 = 10;
113 /// assert!(value.require_non_zero("value").is_ok());
114 ///
115 /// let zero: i32 = 0;
116 /// assert!(zero.require_non_zero("value").is_err());
117 /// ```
118 fn require_non_zero(self, name: &str) -> ArgumentResult<Self>;
119
120 /// Validate that value is positive
121 ///
122 /// # Parameters
123 ///
124 /// * `name` - Parameter name
125 ///
126 /// # Returns
127 ///
128 /// Returns `Ok(self)` if value is greater than zero, otherwise returns an error
129 ///
130 /// # Examples
131 ///
132 /// ```rust,ignore
133 /// use qubit_common::lang::argument::NumericArgument;
134 ///
135 /// let value: i32 = 10;
136 /// assert!(value.require_positive("value").is_ok());
137 ///
138 /// let zero: i32 = 0;
139 /// assert!(zero.require_positive("value").is_err());
140 /// ```
141 fn require_positive(self, name: &str) -> ArgumentResult<Self>;
142
143 /// Validate that value is non-negative
144 ///
145 /// # Parameters
146 ///
147 /// * `name` - Parameter name
148 ///
149 /// # Returns
150 ///
151 /// Returns `Ok(self)` if value is non-negative, otherwise returns an error
152 ///
153 /// # Examples
154 ///
155 /// ```rust,ignore
156 /// use qubit_common::lang::argument::NumericArgument;
157 ///
158 /// let value: i32 = 0;
159 /// assert!(value.require_non_negative("value").is_ok());
160 ///
161 /// let negative: i32 = -5;
162 /// assert!(negative.require_non_negative("value").is_err());
163 /// ```
164 fn require_non_negative(self, name: &str) -> ArgumentResult<Self>;
165
166 /// Validate that value is negative
167 ///
168 /// # Parameters
169 ///
170 /// * `name` - Parameter name
171 ///
172 /// # Returns
173 ///
174 /// Returns `Ok(self)` if value is less than zero, otherwise returns an error
175 ///
176 /// # Examples
177 ///
178 /// ```rust,ignore
179 /// use qubit_common::lang::argument::NumericArgument;
180 ///
181 /// let value: i32 = -5;
182 /// assert!(value.require_negative("value").is_ok());
183 ///
184 /// let positive: i32 = 5;
185 /// assert!(positive.require_negative("value").is_err());
186 /// ```
187 fn require_negative(self, name: &str) -> ArgumentResult<Self>;
188
189 /// Validate that value is non-positive
190 ///
191 /// # Parameters
192 ///
193 /// * `name` - Parameter name
194 ///
195 /// # Returns
196 ///
197 /// Returns `Ok(self)` if value is less than or equal to zero, otherwise returns an error
198 ///
199 /// # Examples
200 ///
201 /// ```rust,ignore
202 /// use qubit_common::lang::argument::NumericArgument;
203 ///
204 /// let value: i32 = 0;
205 /// assert!(value.require_non_positive("value").is_ok());
206 ///
207 /// let negative: i32 = -5;
208 /// assert!(negative.require_non_positive("value").is_ok());
209 ///
210 /// let positive: i32 = 5;
211 /// assert!(positive.require_non_positive("value").is_err());
212 /// ```
213 fn require_non_positive(self, name: &str) -> ArgumentResult<Self>;
214
215 /// Validate that value is within closed interval
216 ///
217 /// # Parameters
218 ///
219 /// * `name` - Parameter name
220 /// * `min` - Minimum value (inclusive)
221 /// * `max` - Maximum value (inclusive)
222 ///
223 /// # Returns
224 ///
225 /// Returns `Ok(self)` if value is within [min, max] range, otherwise returns an error
226 ///
227 /// # Examples
228 ///
229 /// ```rust,ignore
230 /// use qubit_common::lang::argument::NumericArgument;
231 ///
232 /// let value = 50;
233 /// assert!(value.require_in_closed_range("value", 0, 100).is_ok());
234 ///
235 /// let out_of_range = 150;
236 /// assert!(out_of_range.require_in_closed_range("value", 0, 100).is_err());
237 /// ```
238 fn require_in_closed_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self>;
239
240 /// Validate that value is within open interval
241 ///
242 /// # Parameters
243 ///
244 /// * `name` - Parameter name
245 /// * `min` - Minimum value (exclusive)
246 /// * `max` - Maximum value (exclusive)
247 ///
248 /// # Returns
249 ///
250 /// Returns `Ok(self)` if value is within (min, max) range, otherwise returns an error
251 ///
252 /// # Examples
253 ///
254 /// ```rust,ignore
255 /// use qubit_common::lang::argument::NumericArgument;
256 ///
257 /// let value = 50;
258 /// assert!(value.require_in_open_range("value", 0, 100).is_ok());
259 ///
260 /// let boundary = 0;
261 /// assert!(boundary.require_in_open_range("value", 0, 100).is_err());
262 /// ```
263 fn require_in_open_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self>;
264
265 /// Validate that value is within left-open right-closed interval
266 ///
267 /// # Parameters
268 ///
269 /// * `name` - Parameter name
270 /// * `min` - Minimum value (exclusive)
271 /// * `max` - Maximum value (inclusive)
272 ///
273 /// # Returns
274 ///
275 /// Returns `Ok(self)` if value is within (min, max] range, otherwise returns an error
276 ///
277 /// # Examples
278 ///
279 /// ```rust,ignore
280 /// use qubit_common::lang::argument::NumericArgument;
281 ///
282 /// let value = 100;
283 /// assert!(value.require_in_left_open_range("value", 0, 100).is_ok());
284 ///
285 /// let min_boundary = 0;
286 /// assert!(min_boundary.require_in_left_open_range("value", 0, 100).is_err());
287 /// ```
288 fn require_in_left_open_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self>;
289
290 /// Validate that value is within left-closed right-open interval
291 ///
292 /// # Parameters
293 ///
294 /// * `name` - Parameter name
295 /// * `min` - Minimum value (inclusive)
296 /// * `max` - Maximum value (exclusive)
297 ///
298 /// # Returns
299 ///
300 /// Returns `Ok(self)` if value is within [min, max) range, otherwise returns an error
301 ///
302 /// # Examples
303 ///
304 /// ```rust,ignore
305 /// use qubit_common::lang::argument::NumericArgument;
306 ///
307 /// let value = 0;
308 /// assert!(value.require_in_right_open_range("value", 0, 100).is_ok());
309 ///
310 /// let max_boundary = 100;
311 /// assert!(max_boundary.require_in_right_open_range("value", 0, 100).is_err());
312 /// ```
313 fn require_in_right_open_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self>;
314
315 /// Validate that value is less than specified value
316 ///
317 /// # Parameters
318 ///
319 /// * `name` - Parameter name
320 /// * `max` - Maximum value (exclusive)
321 ///
322 /// # Returns
323 ///
324 /// Returns `Ok(self)` if value is less than max, otherwise returns an error
325 ///
326 /// # Examples
327 ///
328 /// ```rust,ignore
329 /// use qubit_common::lang::argument::NumericArgument;
330 ///
331 /// let value = 50;
332 /// assert!(value.require_less("value", 100).is_ok());
333 ///
334 /// let boundary = 100;
335 /// assert!(boundary.require_less("value", 100).is_err());
336 /// ```
337 fn require_less(self, name: &str, max: Self) -> ArgumentResult<Self>;
338
339 /// Validate that value is less than or equal to specified value
340 ///
341 /// # Parameters
342 ///
343 /// * `name` - Parameter name
344 /// * `max` - Maximum value (inclusive)
345 ///
346 /// # Returns
347 ///
348 /// Returns `Ok(self)` if value is less than or equal to max, otherwise returns an error
349 ///
350 /// # Examples
351 ///
352 /// ```rust,ignore
353 /// use qubit_common::lang::argument::NumericArgument;
354 ///
355 /// let value = 100;
356 /// assert!(value.require_less_equal("value", 100).is_ok());
357 ///
358 /// let over = 101;
359 /// assert!(over.require_less_equal("value", 100).is_err());
360 /// ```
361 fn require_less_equal(self, name: &str, max: Self) -> ArgumentResult<Self>;
362
363 /// Validate that value is greater than specified value
364 ///
365 /// # Parameters
366 ///
367 /// * `name` - Parameter name
368 /// * `min` - Minimum value (exclusive)
369 ///
370 /// # Returns
371 ///
372 /// Returns `Ok(self)` if value is greater than min, otherwise returns an error
373 ///
374 /// # Examples
375 ///
376 /// ```rust,ignore
377 /// use qubit_common::lang::argument::NumericArgument;
378 ///
379 /// let value = 50;
380 /// assert!(value.require_greater("value", 0).is_ok());
381 ///
382 /// let boundary = 0;
383 /// assert!(boundary.require_greater("value", 0).is_err());
384 /// ```
385 fn require_greater(self, name: &str, min: Self) -> ArgumentResult<Self>;
386
387 /// Validate that value is greater than or equal to specified value
388 ///
389 /// # Parameters
390 ///
391 /// * `name` - Parameter name
392 /// * `min` - Minimum value (inclusive)
393 ///
394 /// # Returns
395 ///
396 /// Returns `Ok(self)` if value is greater than or equal to min, otherwise returns an error
397 ///
398 /// # Examples
399 ///
400 /// ```rust,ignore
401 /// use qubit_common::lang::argument::NumericArgument;
402 ///
403 /// let value = 0;
404 /// assert!(value.require_greater_equal("value", 0).is_ok());
405 ///
406 /// let under = -1;
407 /// assert!(under.require_greater_equal("value", 0).is_err());
408 /// ```
409 fn require_greater_equal(self, name: &str, min: Self) -> ArgumentResult<Self>;
410}
411
412/// Implement numeric argument validation for all ordered displayable types
413///
414/// Automatically provides validation functionality for types that satisfy `PartialOrd + Default + Display + Copy` constraints.
415/// This includes all standard numeric types: i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64.
416impl<T> NumericArgument for T
417where
418 T: PartialOrd + Default + Display + Copy,
419{
420 fn require_zero(self, name: &str) -> ArgumentResult<Self> {
421 if self != T::default() {
422 return Err(ArgumentError::new(format!(
423 "Parameter '{}' must be zero but was: {}",
424 name, self
425 )));
426 }
427 Ok(self)
428 }
429
430 fn require_non_zero(self, name: &str) -> ArgumentResult<Self> {
431 if self == T::default() {
432 return Err(ArgumentError::new(format!(
433 "Parameter '{}' cannot be zero",
434 name
435 )));
436 }
437 Ok(self)
438 }
439
440 fn require_positive(self, name: &str) -> ArgumentResult<Self> {
441 if self <= T::default() {
442 return Err(ArgumentError::new(format!(
443 "Parameter '{}' must be positive but was: {}",
444 name, self
445 )));
446 }
447 Ok(self)
448 }
449
450 fn require_non_negative(self, name: &str) -> ArgumentResult<Self> {
451 if self < T::default() {
452 return Err(ArgumentError::new(format!(
453 "Parameter '{}' must be non-negative but was: {}",
454 name, self
455 )));
456 }
457 Ok(self)
458 }
459
460 fn require_negative(self, name: &str) -> ArgumentResult<Self> {
461 if self >= T::default() {
462 return Err(ArgumentError::new(format!(
463 "Parameter '{}' must be negative but was: {}",
464 name, self
465 )));
466 }
467 Ok(self)
468 }
469
470 fn require_non_positive(self, name: &str) -> ArgumentResult<Self> {
471 if self > T::default() {
472 return Err(ArgumentError::new(format!(
473 "Parameter '{}' must be non-positive but was: {}",
474 name, self
475 )));
476 }
477 Ok(self)
478 }
479
480 fn require_in_closed_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self> {
481 if self < min || self > max {
482 return Err(ArgumentError::new(format!(
483 "Parameter '{}' must be in range [{}, {}] but was: {}",
484 name, min, max, self
485 )));
486 }
487 Ok(self)
488 }
489
490 fn require_in_open_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self> {
491 if self <= min || self >= max {
492 return Err(ArgumentError::new(format!(
493 "Parameter '{}' must be in range ({}, {}) but was: {}",
494 name, min, max, self
495 )));
496 }
497 Ok(self)
498 }
499
500 fn require_in_left_open_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self> {
501 if self <= min || self > max {
502 return Err(ArgumentError::new(format!(
503 "Parameter '{}' must be in range ({}, {}] but was: {}",
504 name, min, max, self
505 )));
506 }
507 Ok(self)
508 }
509
510 fn require_in_right_open_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self> {
511 if self < min || self >= max {
512 return Err(ArgumentError::new(format!(
513 "Parameter '{}' must be in range [{}, {}) but was: {}",
514 name, min, max, self
515 )));
516 }
517 Ok(self)
518 }
519
520 fn require_less(self, name: &str, max: Self) -> ArgumentResult<Self> {
521 if self >= max {
522 return Err(ArgumentError::new(format!(
523 "Parameter '{}' must be less than {} but was: {}",
524 name, max, self
525 )));
526 }
527 Ok(self)
528 }
529
530 fn require_less_equal(self, name: &str, max: Self) -> ArgumentResult<Self> {
531 if self > max {
532 return Err(ArgumentError::new(format!(
533 "Parameter '{}' must be less than or equal to {} but was: {}",
534 name, max, self
535 )));
536 }
537 Ok(self)
538 }
539
540 fn require_greater(self, name: &str, min: Self) -> ArgumentResult<Self> {
541 if self <= min {
542 return Err(ArgumentError::new(format!(
543 "Parameter '{}' must be greater than {} but was: {}",
544 name, min, self
545 )));
546 }
547 Ok(self)
548 }
549
550 fn require_greater_equal(self, name: &str, min: Self) -> ArgumentResult<Self> {
551 if self < min {
552 return Err(ArgumentError::new(format!(
553 "Parameter '{}' must be greater than or equal to {} but was: {}",
554 name, min, self
555 )));
556 }
557 Ok(self)
558 }
559}
560
561/// Comparison argument validation
562///
563/// Provides comparison validation functionality between two arguments.
564///
565/// # Examples
566///
567/// ```rust,ignore
568/// use qubit_common::lang::argument::require_equal;
569///
570/// let result = require_equal("width", 100, "height", 100);
571/// assert!(result.is_ok());
572///
573/// let result = require_equal("width", 100, "height", 200);
574/// assert!(result.is_err());
575/// ```
576///
577/// # Author
578///
579/// Haixing Hu
580pub fn require_equal<T>(name1: &str, value1: T, name2: &str, value2: T) -> ArgumentResult<()>
581where
582 T: PartialEq + Display,
583{
584 if value1 != value2 {
585 return Err(ArgumentError::new(format!(
586 "Parameter '{}' ({}) must equal parameter '{}' ({})",
587 name1, value1, name2, value2
588 )));
589 }
590 Ok(())
591}
592
593/// Validate that two arguments are not equal
594///
595/// # Parameters
596///
597/// * `name1` - First parameter name
598/// * `value1` - First parameter value
599/// * `name2` - Second parameter name
600/// * `value2` - Second parameter value
601///
602/// # Examples
603///
604/// ```rust,ignore
605/// use qubit_common::lang::argument::require_not_equal;
606///
607/// let result = require_not_equal("min", 0, "max", 100);
608/// assert!(result.is_ok());
609/// ```
610///
611/// # Author
612///
613/// Haixing Hu
614pub fn require_not_equal<T>(name1: &str, value1: T, name2: &str, value2: T) -> ArgumentResult<()>
615where
616 T: PartialEq + Display,
617{
618 if value1 == value2 {
619 return Err(ArgumentError::new(format!(
620 "Parameters '{}' and '{}' cannot be equal (both are: {})",
621 name1, name2, value1
622 )));
623 }
624 Ok(())
625}