1use crate::span::Span;
4use schemars_crate::schema::{InstanceType, Metadata, SingleOrVec};
5use std::ops::AddAssign;
6
7#[derive(Debug, Clone, PartialEq)]
11pub struct Error<S: Span> {
12 pub meta: Option<Box<Metadata>>,
15
16 pub span: Option<S>,
18
19 pub value: ErrorValue<S>,
21}
22
23impl<S: Span> Error<S> {
24 pub(crate) fn new(meta: Option<Box<Metadata>>, span: Option<S>, value: ErrorValue<S>) -> Self {
25 Self { meta, span, value }
26 }
27}
28
29impl<S: Span> core::fmt::Display for Error<S> {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 let mut start_paren = false;
32
33 if f.alternate() {
34 if let Some(span) = &self.span {
35 write!(f, "({:?}", span)?;
36 start_paren = true;
37 }
38
39 if let Some(meta) = &self.meta {
40 if let Some(title) = &meta.title {
41 if start_paren {
42 write!(f, r#", schema: "{}""#, title)?;
43 } else {
44 write!(f, r#"(schema: "{}""#, title)?;
45 }
46 start_paren = true;
47 }
48 }
49 }
50
51 if start_paren {
52 write!(f, ") ")?;
53 }
54
55 write!(f, "{}", self.value)
56 }
57}
58
59#[derive(Debug, Clone, PartialEq)]
61pub enum ErrorValue<S: Span> {
63 Never,
65
66 UnknownProperty,
68
69 InvalidSchema(InvalidSchema),
71
72 UnsupportedValue(UnsupportedValue),
75
76 InvalidType {
78 expected: SingleOrVec<InstanceType>,
79 actual: InstanceType,
80 },
81
82 InvalidEnumValue { expected: Vec<serde_json::Value> },
84
85 NotMultipleOf { multiple_of: f64 },
87
88 LessThanExpected { min: f64, exclusive: bool },
90
91 MoreThanExpected { max: f64, exclusive: bool },
93
94 NoPatternMatch { pattern: String },
96
97 TooLong { max_length: u32 },
99
100 TooShort { min_length: u32 },
102
103 NoneValid {
107 exclusive: bool,
108 schemas: Vec<Option<Box<Metadata>>>,
109 errors: Vec<Errors<S>>,
110 },
111
112 MoreThanOneValid { schemas: Vec<Option<Box<Metadata>>>, matched: Vec<Option<Box<Metadata>>> },
114
115 ValidNot { matched: Option<Box<Metadata>> },
117
118 NotUnique {
120 first: Option<S>,
121 duplicate: Option<S>,
122 },
123
124 MustContain { schema: Option<Box<Metadata>> },
126
127 NotEnoughItems { min: usize },
129
130 TooManyItems { max: usize },
132
133 NotEnoughProperties { min: usize },
135
136 TooManyProperties { max: usize },
138
139 RequiredProperty { name: String },
141
142 Custom(String),
144}
145
146#[derive(Debug, Clone, PartialEq)]
149pub enum UnsupportedValue {
150 KeyNotString,
152}
153
154impl core::fmt::Display for UnsupportedValue {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 match self {
157 UnsupportedValue::KeyNotString => write!(f, "map key must be a string"),
158 }
159 }
160}
161
162#[derive(Debug, Clone, PartialEq)]
169pub enum InvalidSchema {
170 MissingDefinition(String),
172
173 InvalidPattern {
175 pattern: String,
176 error: regex::Error,
177 },
178
179 ExternalReference(String),
181}
182
183impl core::fmt::Display for InvalidSchema {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 match self {
186 InvalidSchema::MissingDefinition(s) => write!(f, r#"missing local definition "{}""#, s),
187 InvalidSchema::InvalidPattern { pattern, error } => {
188 write!(f, r#"invalid regex pattern "{}": {}"#, pattern, error)
189 }
190 InvalidSchema::ExternalReference(r) => write!(
191 f,
192 r#"the schema contains unresolved external reference: "{}""#,
193 r
194 ),
195 }
196 }
197}
198
199impl<S: Span> core::fmt::Display for ErrorValue<S> {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 match self {
202 ErrorValue::Never => write!(f, "no values allowed"),
203 ErrorValue::UnknownProperty => write!(f, "unknown property"),
204 ErrorValue::InvalidSchema(err) => write!(f, "invalid schema: {}", err),
205 ErrorValue::UnsupportedValue(err) => write!(f, "unsupported value: {}", err),
206 ErrorValue::InvalidType { expected, actual } => write!(
207 f,
208 r#"invalid type, expected {}, not "{:?}""#,
209 match expected {
210 SingleOrVec::Single(s) => {
211 format!(r#""{:?}""#, s)
212 }
213 SingleOrVec::Vec(v) => {
214 let mut s = "one of {".into();
215
216 for (i, t) in v.iter().enumerate() {
217 s += format!(r#""{:?}""#, t).as_str();
218 if i != v.len() - 1 {
219 s += ", "
220 }
221 }
222 s += "}";
223
224 s
225 }
226 },
227 actual
228 ),
229 ErrorValue::InvalidEnumValue { expected } => {
230 let enum_vals: Vec<String> = expected.iter().map(|v| v.to_string()).collect();
231 write!(
232 f,
233 "invalid enum value, expected to be one of {{{}}}",
234 enum_vals.join(", ")
235 )
236 }
237 ErrorValue::NotMultipleOf { multiple_of } => {
238 write!(f, "the value is expected to be multiple of {}", multiple_of)
239 }
240 ErrorValue::LessThanExpected { min, exclusive } => {
241 if *exclusive {
242 write!(f, "the value is expected to be more than {}", min)
243 } else {
244 write!(f, "the value is expected to be at least {}", min)
245 }
246 }
247 ErrorValue::MoreThanExpected { max, exclusive } => {
248 if *exclusive {
249 write!(f, "the value is expected to be less than {}", max)
250 } else {
251 write!(f, "the value is expected to be at most {}", max)
252 }
253 }
254 ErrorValue::NoPatternMatch { pattern } => {
255 write!(f, r#"the string must match the pattern "{}""#, pattern)
256 }
257 ErrorValue::TooLong { max_length } => write!(
258 f,
259 r#"the string must not be longer than {} characters"#,
260 max_length
261 ),
262 ErrorValue::TooShort { min_length } => write!(
263 f,
264 r#"the string must must be at least {} characters long"#,
265 min_length
266 ),
267 ErrorValue::NoneValid {
268 exclusive: _,
269 schemas: _,
270 errors,
271 } => {
272 writeln!(f, r#"no subschema matched the value:"#)?;
273
274 for (i, e) in errors.iter().enumerate() {
275 write!(f, "{}", e)?;
276
277 if i != errors.len() - 1 {
278 writeln!(f, "\n")?;
279 }
280 }
281
282 Ok(())
283 }
284 ErrorValue::MoreThanOneValid { schemas: _, matched } => writeln!(
285 f,
286 r#"expected exactly one schema to match, but {} schemas matched"#,
287 matched.len()
288 ),
289 ErrorValue::ValidNot { matched } => {
290 if let Some(meta) = matched {
291 if let Some(title) = &meta.title {
292 return writeln!(f, r#"the value must not be a "{}""#, title);
293 }
294 }
295
296 writeln!(f, r#"the value is disallowed by a "not" schema"#)
297 }
298 ErrorValue::NotUnique { first: _, duplicate: _ } => {
299 writeln!(f, r#"all items in the array must be unique"#)
300 }
301 ErrorValue::MustContain { schema } => {
302 if let Some(meta) = schema {
303 if let Some(title) = &meta.title {
304 return writeln!(
305 f,
306 r#"at least one of the items in the array must be "{}""#,
307 title
308 );
309 }
310 }
311
312 writeln!(
313 f,
314 r#"at least one of the items in the array must match the given schema"#
315 )
316 }
317 ErrorValue::NotEnoughItems { min } => {
318 write!(f, "the array must have at least {} items", min)
319 }
320 ErrorValue::TooManyItems { max } => {
321 write!(f, "the array cannot have more than {} items", max)
322 }
323 ErrorValue::NotEnoughProperties { min } => {
324 write!(f, "the object must have at least {} properties", min)
325 }
326 ErrorValue::TooManyProperties { max } => {
327 write!(f, "the object cannot have more than {} properties", max)
328 }
329 ErrorValue::RequiredProperty { name } => {
330 write!(f, r#"the required property "{}" is missing"#, name)
331 }
332 ErrorValue::Custom(err) => err.fmt(f),
333 }
334 }
335}
336
337#[cfg(feature = "smallvec")]
338type SmallVecArray<S> = [Error<S>; 10];
339
340#[cfg(feature = "smallvec")]
341pub(super) type ErrorsInner<S> = smallvec_crate::SmallVec<SmallVecArray<S>>;
344
345#[cfg(not(feature = "smallvec"))]
346pub(super) type ErrorsInner<S> = Vec<Error<S>>;
347
348#[derive(Debug, Clone, PartialEq)]
350#[repr(transparent)]
351pub struct Errors<S: Span>(pub(crate) ErrorsInner<S>);
352
353impl<S: Span> Errors<S> {
354 pub fn is_empty(&self) -> bool {
355 self.0.is_empty()
356 }
357
358 pub fn len(&self) -> usize {
359 self.0.len()
360 }
361
362 pub fn iter(&self) -> impl Iterator<Item = &Error<S>> {
363 self.0.iter()
364 }
365
366 pub(super) fn new() -> Self {
367 Errors(ErrorsInner::new())
368 }
369
370 pub(super) fn one(error: Error<S>) -> Self {
371 let mut v = ErrorsInner::new();
372 v.push(error);
373 Errors(v)
374 }
375}
376
377impl<S: Span> IntoIterator for Errors<S> {
378 type Item = <ErrorsInner<S> as IntoIterator>::Item;
379
380 #[cfg(feature = "smallvec")]
381 type IntoIter = smallvec_crate::IntoIter<SmallVecArray<S>>;
382
383 #[cfg(not(feature = "smallvec"))]
384 type IntoIter = std::vec::IntoIter<Error<S>>;
385
386 fn into_iter(self) -> Self::IntoIter {
387 self.0.into_iter()
388 }
389}
390
391impl<S: Span> core::fmt::Display for Errors<S> {
392 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
393 for e in &self.0 {
394 writeln!(f, "{}", e)?;
395 }
396 Ok(())
397 }
398}
399
400impl<S: Span> std::error::Error for Errors<S> {}
401impl<S: Span> crate::Error for Errors<S> {
402 fn custom<T: core::fmt::Display>(error: T) -> Self {
403 Self::one(Error::new(
404 None,
405 None,
406 ErrorValue::Custom(error.to_string()),
407 ))
408 }
409}
410
411impl<S: Span> AddAssign for Errors<S> {
412 fn add_assign(&mut self, rhs: Self) {
413 self.0.extend(rhs.0.into_iter());
414 }
415}