toasty_core/error/
validation.rs

1use super::Error;
2
3/// Error when a value fails validation constraints.
4#[derive(Debug)]
5pub(super) struct ValidationFailed {
6    kind: ValidationFailedKind,
7}
8
9#[derive(Debug)]
10pub(super) enum ValidationFailedKind {
11    /// String length constraint violation
12    Length {
13        value_len: usize,
14        min: Option<usize>,
15        max: Option<usize>,
16    },
17    /// General validation failure with message
18    Message { message: Box<str> },
19}
20
21impl std::error::Error for ValidationFailed {}
22
23impl core::fmt::Display for ValidationFailed {
24    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
25        match &self.kind {
26            ValidationFailedKind::Length {
27                value_len,
28                min,
29                max,
30            } => {
31                // If min and max are the same, show exact length requirement
32                if min == max && min.is_some() {
33                    let expected = min.unwrap();
34                    return write!(
35                        f,
36                        "value length {} does not match required length {}",
37                        value_len, expected
38                    );
39                }
40
41                // Check which constraint was violated
42                let too_short = min.is_some_and(|m| *value_len < m);
43                let too_long = max.is_some_and(|m| *value_len > m);
44
45                if too_short {
46                    write!(
47                        f,
48                        "value length {} is too short (minimum: {})",
49                        value_len,
50                        min.unwrap()
51                    )
52                } else if too_long {
53                    write!(
54                        f,
55                        "value length {} is too long (maximum: {})",
56                        value_len,
57                        max.unwrap()
58                    )
59                } else {
60                    f.write_str("length constraint violation")
61                }
62            }
63            ValidationFailedKind::Message { message } => {
64                write!(f, "validation failed: {}", message)
65            }
66        }
67    }
68}
69
70impl Error {
71    /// Creates a general validation error with a custom message.
72    ///
73    /// # Examples
74    ///
75    /// ```
76    /// use toasty_core::Error;
77    ///
78    /// let err = Error::validation_failed("email format invalid");
79    /// assert!(err.is_validation());
80    /// assert_eq!(err.to_string(), "validation failed: email format invalid");
81    /// ```
82    pub fn validation_failed(message: impl Into<String>) -> Error {
83        Error::from(super::ErrorKind::ValidationFailed(ValidationFailed {
84            kind: ValidationFailedKind::Message {
85                message: message.into().into(),
86            },
87        }))
88    }
89
90    /// Creates a validation error for a length constraint violation.
91    ///
92    /// This is used when a string value violates minimum or maximum length constraints.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// use toasty_core::Error;
98    ///
99    /// // Value too short
100    /// let err = Error::validation_length(2, Some(5), Some(100));
101    /// assert_eq!(err.to_string(), "value length 2 is too short (minimum: 5)");
102    ///
103    /// // Value too long
104    /// let err = Error::validation_length(150, Some(5), Some(100));
105    /// assert_eq!(err.to_string(), "value length 150 is too long (maximum: 100)");
106    /// ```
107    pub fn validation_length(value_len: usize, min: Option<usize>, max: Option<usize>) -> Error {
108        Error::from(super::ErrorKind::ValidationFailed(ValidationFailed {
109            kind: ValidationFailedKind::Length {
110                value_len,
111                min,
112                max,
113            },
114        }))
115    }
116
117    /// Returns `true` if this error is a validation error.
118    pub fn is_validation(&self) -> bool {
119        matches!(self.kind(), super::ErrorKind::ValidationFailed(_))
120    }
121}