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 #[inline]
421 fn require_zero(self, name: &str) -> ArgumentResult<Self> {
422 if self != T::default() {
423 return Err(ArgumentError::new(format!(
424 "Parameter '{}' must be zero but was: {}",
425 name, self
426 )));
427 }
428 Ok(self)
429 }
430
431 #[inline]
432 fn require_non_zero(self, name: &str) -> ArgumentResult<Self> {
433 if self == T::default() {
434 return Err(ArgumentError::new(format!(
435 "Parameter '{}' cannot be zero",
436 name
437 )));
438 }
439 Ok(self)
440 }
441
442 #[inline]
443 fn require_positive(self, name: &str) -> ArgumentResult<Self> {
444 if self <= T::default() {
445 return Err(ArgumentError::new(format!(
446 "Parameter '{}' must be positive but was: {}",
447 name, self
448 )));
449 }
450 Ok(self)
451 }
452
453 #[inline]
454 fn require_non_negative(self, name: &str) -> ArgumentResult<Self> {
455 if self < T::default() {
456 return Err(ArgumentError::new(format!(
457 "Parameter '{}' must be non-negative but was: {}",
458 name, self
459 )));
460 }
461 Ok(self)
462 }
463
464 #[inline]
465 fn require_negative(self, name: &str) -> ArgumentResult<Self> {
466 if self >= T::default() {
467 return Err(ArgumentError::new(format!(
468 "Parameter '{}' must be negative but was: {}",
469 name, self
470 )));
471 }
472 Ok(self)
473 }
474
475 #[inline]
476 fn require_non_positive(self, name: &str) -> ArgumentResult<Self> {
477 if self > T::default() {
478 return Err(ArgumentError::new(format!(
479 "Parameter '{}' must be non-positive but was: {}",
480 name, self
481 )));
482 }
483 Ok(self)
484 }
485
486 #[inline]
487 fn require_in_closed_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self> {
488 if self < min || self > max {
489 return Err(ArgumentError::new(format!(
490 "Parameter '{}' must be in range [{}, {}] but was: {}",
491 name, min, max, self
492 )));
493 }
494 Ok(self)
495 }
496
497 #[inline]
498 fn require_in_open_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self> {
499 if self <= min || self >= max {
500 return Err(ArgumentError::new(format!(
501 "Parameter '{}' must be in range ({}, {}) but was: {}",
502 name, min, max, self
503 )));
504 }
505 Ok(self)
506 }
507
508 #[inline]
509 fn require_in_left_open_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self> {
510 if self <= min || self > max {
511 return Err(ArgumentError::new(format!(
512 "Parameter '{}' must be in range ({}, {}] but was: {}",
513 name, min, max, self
514 )));
515 }
516 Ok(self)
517 }
518
519 #[inline]
520 fn require_in_right_open_range(self, name: &str, min: Self, max: Self) -> ArgumentResult<Self> {
521 if self < min || self >= max {
522 return Err(ArgumentError::new(format!(
523 "Parameter '{}' must be in range [{}, {}) but was: {}",
524 name, min, max, self
525 )));
526 }
527 Ok(self)
528 }
529
530 #[inline]
531 fn require_less(self, name: &str, max: Self) -> ArgumentResult<Self> {
532 if self >= max {
533 return Err(ArgumentError::new(format!(
534 "Parameter '{}' must be less than {} but was: {}",
535 name, max, self
536 )));
537 }
538 Ok(self)
539 }
540
541 #[inline]
542 fn require_less_equal(self, name: &str, max: Self) -> ArgumentResult<Self> {
543 if self > max {
544 return Err(ArgumentError::new(format!(
545 "Parameter '{}' must be less than or equal to {} but was: {}",
546 name, max, self
547 )));
548 }
549 Ok(self)
550 }
551
552 #[inline]
553 fn require_greater(self, name: &str, min: Self) -> ArgumentResult<Self> {
554 if self <= min {
555 return Err(ArgumentError::new(format!(
556 "Parameter '{}' must be greater than {} but was: {}",
557 name, min, self
558 )));
559 }
560 Ok(self)
561 }
562
563 #[inline]
564 fn require_greater_equal(self, name: &str, min: Self) -> ArgumentResult<Self> {
565 if self < min {
566 return Err(ArgumentError::new(format!(
567 "Parameter '{}' must be greater than or equal to {} but was: {}",
568 name, min, self
569 )));
570 }
571 Ok(self)
572 }
573}
574
575/// Comparison argument validation
576///
577/// Provides comparison validation functionality between two arguments.
578///
579/// # Examples
580///
581/// ```rust,ignore
582/// use qubit_common::lang::argument::require_equal;
583///
584/// let result = require_equal("width", 100, "height", 100);
585/// assert!(result.is_ok());
586///
587/// let result = require_equal("width", 100, "height", 200);
588/// assert!(result.is_err());
589/// ```
590///
591/// # Author
592///
593/// Haixing Hu
594#[inline]
595pub fn require_equal<T>(name1: &str, value1: T, name2: &str, value2: T) -> ArgumentResult<()>
596where
597 T: PartialEq + Display,
598{
599 if value1 != value2 {
600 return Err(ArgumentError::new(format!(
601 "Parameter '{}' ({}) must equal parameter '{}' ({})",
602 name1, value1, name2, value2
603 )));
604 }
605 Ok(())
606}
607
608/// Validate that two arguments are not equal
609///
610/// # Parameters
611///
612/// * `name1` - First parameter name
613/// * `value1` - First parameter value
614/// * `name2` - Second parameter name
615/// * `value2` - Second parameter value
616///
617/// # Examples
618///
619/// ```rust,ignore
620/// use qubit_common::lang::argument::require_not_equal;
621///
622/// let result = require_not_equal("min", 0, "max", 100);
623/// assert!(result.is_ok());
624/// ```
625///
626/// # Author
627///
628/// Haixing Hu
629#[inline]
630pub fn require_not_equal<T>(name1: &str, value1: T, name2: &str, value2: T) -> ArgumentResult<()>
631where
632 T: PartialEq + Display,
633{
634 if value1 == value2 {
635 return Err(ArgumentError::new(format!(
636 "Parameters '{}' and '{}' cannot be equal (both are: {})",
637 name1, name2, value1
638 )));
639 }
640 Ok(())
641}