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}