Skip to main content

karbon_framework/validation/constraints/number/
numeric.rs

1use crate::validation::constraints::{Constraint, ConstraintResult, ConstraintViolation};
2
3/// Validates that a value is numeric (integer or float).
4pub struct Numeric {
5    pub message: String,
6    pub allow_float: bool,
7}
8
9impl Default for Numeric {
10    fn default() -> Self {
11        Self {
12            message: "This value should be a valid number.".to_string(),
13            allow_float: true,
14        }
15    }
16}
17
18impl Numeric {
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    /// Only allow integer values
24    pub fn integer_only() -> Self {
25        Self {
26            allow_float: false,
27            ..Self::default()
28        }
29    }
30
31    pub fn with_message(mut self, message: impl Into<String>) -> Self {
32        self.message = message.into();
33        self
34    }
35}
36
37impl Constraint for Numeric {
38    fn validate(&self, value: &str) -> ConstraintResult {
39        let valid = if self.allow_float {
40            value.parse::<f64>().is_ok()
41        } else {
42            value.parse::<i64>().is_ok()
43        };
44
45        if !valid {
46            return Err(ConstraintViolation::new(
47                self.name(),
48                &self.message,
49                value,
50            ));
51        }
52        Ok(())
53    }
54
55    fn name(&self) -> &'static str {
56        "Numeric"
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_valid_numbers() {
66        let constraint = Numeric::new();
67        assert!(constraint.validate("42").is_ok());
68        assert!(constraint.validate("-10").is_ok());
69        assert!(constraint.validate("3.14").is_ok());
70        assert!(constraint.validate("0").is_ok());
71        assert!(constraint.validate("-0.5").is_ok());
72    }
73
74    #[test]
75    fn test_invalid_numbers() {
76        let constraint = Numeric::new();
77        assert!(constraint.validate("").is_err());
78        assert!(constraint.validate("abc").is_err());
79        assert!(constraint.validate("12abc").is_err());
80        assert!(constraint.validate("12.34.56").is_err());
81    }
82
83    #[test]
84    fn test_integer_only() {
85        let constraint = Numeric::integer_only();
86        assert!(constraint.validate("42").is_ok());
87        assert!(constraint.validate("-10").is_ok());
88        assert!(constraint.validate("3.14").is_err());
89        assert!(constraint.validate("0.5").is_err());
90    }
91}