1pub mod issue;
2pub mod result;
3
4use crate::{
5 locales::{localizer, Locale},
6 ValidationIssue,
7};
8use serde_json::Value;
9use std::fmt;
10
11#[derive(Debug, Clone, PartialEq)]
12pub enum ValidationError {
13 Required,
14 InvalidType {
15 expected: ValidationType,
16 input: ValidationType,
17 },
18 InvalidValue {
19 value: String,
20 },
21 InvalidValues {
22 values: Vec<String>,
23 },
24 TooBig {
25 origin: ValidationOrigin,
26 maximum: String,
27 inclusive: bool,
28 },
29 TooSmall {
30 origin: ValidationOrigin,
31 minimum: String,
32 inclusive: bool,
33 },
34 InvalidFormat {
35 format: StringFormat,
36 detail: Option<String>,
37 },
38 InvalidNumber {
39 constraint: NumberConstraint,
40 },
41 UnrecognizedKeys {
42 keys: Vec<String>,
43 },
44 InvalidUnion {
45 issues: Vec<ValidationIssue>,
46 },
47 Custom {
48 message: String,
49 },
50}
51
52impl ValidationError {
53 pub fn local(&self, locale: Locale) -> String {
54 localizer(locale).localize(self)
55 }
56}
57
58impl fmt::Display for ValidationError {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(f, "{}", self.local(Locale::En))?;
61 Ok(())
62 }
63}
64
65impl ValidationError {
66 pub fn required() -> Self {
67 Self::Required
68 }
69
70 pub fn invalid_type(expected: ValidationType, input: ValidationType) -> Self {
71 Self::InvalidType { expected, input }
72 }
73
74 pub fn invalid_value(value: impl Into<String>) -> Self {
75 Self::InvalidValue {
76 value: value.into(),
77 }
78 }
79
80 pub fn invalid_values(values: Vec<String>) -> Self {
81 Self::InvalidValues { values }
82 }
83
84 pub fn too_big(origin: ValidationOrigin, maximum: impl Into<String>, inclusive: bool) -> Self {
85 Self::TooBig {
86 origin,
87 maximum: maximum.into(),
88 inclusive,
89 }
90 }
91
92 pub fn too_small(
93 origin: ValidationOrigin,
94 minimum: impl Into<String>,
95 inclusive: bool,
96 ) -> Self {
97 Self::TooSmall {
98 origin,
99 minimum: minimum.into(),
100 inclusive,
101 }
102 }
103
104 pub fn invalid_format(format: StringFormat, detail: Option<String>) -> Self {
105 Self::InvalidFormat { format, detail }
106 }
107
108 pub fn invalid_number(constraint: NumberConstraint) -> Self {
109 Self::InvalidNumber { constraint }
110 }
111
112 pub fn unrecognized_keys(keys: Vec<String>) -> Self {
113 Self::UnrecognizedKeys { keys }
114 }
115
116 pub fn invalid_union(issues: Vec<ValidationIssue>) -> Self {
117 Self::InvalidUnion { issues }
118 }
119
120 pub fn custom(message: impl Into<String>) -> Self {
121 Self::Custom {
122 message: message.into(),
123 }
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq, Hash)]
128pub enum ValidationOrigin {
129 String,
130 Array,
131 Number,
132}
133
134impl fmt::Display for ValidationOrigin {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 let value = match self {
137 ValidationOrigin::String => "string",
138 ValidationOrigin::Array => "array",
139 ValidationOrigin::Number => "number",
140 };
141
142 write!(f, "{value}")?;
143 Ok(())
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, Hash)]
148pub enum ValidationType {
149 Null,
150 Bool,
151 Number,
152 String,
153 Array,
154 Object,
155 Undefined,
156 Custom(String),
157}
158
159impl ValidationType {
160 pub fn custom(val_type: impl Into<String>) -> Self {
161 Self::Custom(val_type.into())
162 }
163}
164
165impl From<&Value> for ValidationType {
166 fn from(value: &Value) -> Self {
167 match value {
168 Value::Null => ValidationType::Null,
169 Value::Bool(_) => ValidationType::Bool,
170 Value::Number(_) => ValidationType::Number,
171 Value::String(_) => ValidationType::String,
172 Value::Array(_) => ValidationType::Array,
173 Value::Object(_) => ValidationType::Object,
174 }
175 }
176}
177
178impl fmt::Display for ValidationType {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 let value = match self {
181 ValidationType::Null => "null",
182 ValidationType::Bool => "bool",
183 ValidationType::Number => "number",
184 ValidationType::String => "string",
185 ValidationType::Array => "array",
186 ValidationType::Object => "object",
187 ValidationType::Undefined => "undefined",
188 ValidationType::Custom(_type) => _type,
189 };
190
191 write!(f, "{value}")?;
192 Ok(())
193 }
194}
195
196#[derive(Debug, Clone, PartialEq, Eq, Hash)]
197pub enum StringFormat {
198 StartsWith,
199 EndsWith,
200 Includes,
201 Regex,
202 Custom(String),
203}
204
205impl StringFormat {
206 pub fn custom(val_type: impl Into<String>) -> Self {
207 Self::Custom(val_type.into())
208 }
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, Hash)]
212pub enum NumberConstraint {
213 Finite,
214 Positive,
215 Negative,
216 NonNegative,
217 NonPositive,
218}
219
220#[derive(Debug)]
223pub enum ParseError {
224 Json(serde_json::Error),
226 Validation(result::ValidationResult),
228}
229
230impl fmt::Display for ParseError {
231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232 match self {
233 ParseError::Json(e) => write!(f, "JSON parsing error: {}", e),
234 ParseError::Validation(e) => write!(f, "Validation error: {}", e),
235 }
236 }
237}
238
239impl std::error::Error for ParseError {
240 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
241 match self {
242 ParseError::Json(e) => Some(e),
243 ParseError::Validation(e) => Some(e),
244 }
245 }
246}
247
248impl From<serde_json::Error> for ParseError {
249 fn from(e: serde_json::Error) -> Self {
250 ParseError::Json(e)
251 }
252}
253
254impl From<result::ValidationResult> for ParseError {
255 fn from(e: result::ValidationResult) -> Self {
256 ParseError::Validation(e)
257 }
258}