deser_core/error.rs
1//! Error interface.
2use alloc::borrow::Cow;
3use alloc::boxed::Box;
4use alloc::format;
5use alloc::string::String;
6use alloc::vec::Vec;
7use core::any::{Any, TypeId};
8use core::fmt;
9
10use crate::{Position, State};
11
12/// Describes the kind of error.
13#[derive(Debug, Eq, PartialEq, Copy, Clone)]
14pub enum ErrorKind {
15 UnsupportedType,
16 Unexpected,
17 MissingField,
18 OutOfRange,
19 WrongLength,
20 EndOfFile,
21 /// Reading or writing failed (see `deser::io`). The IO error is
22 /// the [`source`](std::error::Error::source) of the error.
23 Io,
24}
25
26/// Additional information attached to an [`Error`].
27///
28/// Besides the location in the input, which is built into errors, layers
29/// and other code can attach typed values to errors with
30/// [`Error::with_attachment`] and retrieve them with
31/// [`Error::attachment`]. An error holds at most one attachment per type.
32/// For instance the `deser-path` crate attaches the path of the value an
33/// error refers to.
34///
35/// Attachments can contribute to the [`Display`](fmt::Display) output of
36/// the error with [`fmt_context`](Self::fmt_context).
37///
38/// ```
39/// use std::fmt;
40/// use deser::{Error, ErrorAttachment, ErrorKind};
41///
42/// #[derive(Debug)]
43/// struct FileName(String);
44///
45/// impl ErrorAttachment for FileName {
46/// fn fmt_context(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47/// write!(f, " in {}", self.0)
48/// }
49/// }
50///
51/// let err = Error::new(ErrorKind::Unexpected, "unexpected string")
52/// .with_position(12, 2, 5)
53/// .with_attachment(FileName("config.json".into()));
54/// assert_eq!(err.attachment::<FileName>().unwrap().0, "config.json");
55/// assert_eq!(
56/// err.to_string(),
57/// "Unexpected: unexpected string at line 2 column 5 in config.json"
58/// );
59/// ```
60pub trait ErrorAttachment: Any + fmt::Debug + Send + Sync {
61 /// Writes the attachment as part of the error message.
62 ///
63 /// The output is appended to the message and the location of the
64 /// error, so it typically starts with a space. By default attachments
65 /// are not shown.
66 fn fmt_context(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 let _ = f;
68 Ok(())
69 }
70}
71
72/// Adds context to errors, see [`State::add_error_context`](crate::State::add_error_context).
73///
74/// This is typically implemented by the extension type which holds the
75/// information that is attached to errors.
76pub trait ErrorContext: 'static {
77 /// Adds context to an error.
78 ///
79 /// This is invoked with the state as it was when the error happened.
80 /// Context that is already attached to the error should not be
81 /// replaced.
82 fn add_context(err: Error, state: &State) -> Error;
83}
84
85/// An error for deser.
86///
87/// Besides a kind and a message an error can carry context: the location
88/// in the input it refers to (see [`offset`](Self::offset),
89/// [`line`](Self::line) and [`column`](Self::column)) and typed
90/// attachments (see [`ErrorAttachment`]). The context is part of the
91/// [`Display`](fmt::Display) output:
92///
93/// ```
94/// use deser::{Error, ErrorKind};
95///
96/// let err = Error::new(ErrorKind::Unexpected, "unexpected string")
97/// .with_position(12, 2, 5);
98/// assert_eq!(
99/// err.to_string(),
100/// "Unexpected: unexpected string at line 2 column 5"
101/// );
102/// ```
103///
104/// Errors raised while deserializing a value (for instance by a
105/// [`Sink`](crate::de::Sink)) get the context attached by the
106/// [`DeserializeDriver`](crate::de::DeserializeDriver): the start of the
107/// input range of the event (see [`State::input_range`](crate::State::input_range))
108/// and the context of the types registered with
109/// [`State::add_error_context`](crate::State::add_error_context). Formats
110/// resolve the offsets into lines and columns.
111///
112/// # Multiple Errors
113///
114/// An error can hold multiple errors, for instance if deserialization
115/// continued after an error to report all problems of the input at once
116/// (see [`State::set_collect_errors`](crate::State::set_collect_errors)).
117/// The accessors ([`kind`](Self::kind), [`message`](Self::message), the
118/// location and the attachments) refer to the first of them, all of them
119/// are iterated with [`errors`](Self::errors). The
120/// [`Display`](fmt::Display) output mentions how many more errors there
121/// are, with the alternate flag (`{:#}`) it lists all of them, one per
122/// line:
123///
124/// ```
125/// use deser::{Error, ErrorKind};
126///
127/// let err = Error::from_errors([
128/// Error::new(ErrorKind::MissingField, "missing field `a`")
129/// .with_offset(0),
130/// Error::new(ErrorKind::Unexpected, "unexpected string")
131/// .with_offset(9),
132/// ])
133/// .unwrap()
134/// .resolve_position(b"{\n \"b\": \"x\"}");
135/// assert_eq!(err.error_count(), 2);
136/// assert_eq!(err.kind(), ErrorKind::MissingField);
137/// assert_eq!(
138/// err.to_string(),
139/// "MissingField: missing field `a` at line 1 column 1 \
140/// (and 1 more error)"
141/// );
142/// assert_eq!(
143/// format!("{:#}", err),
144/// "MissingField: missing field `a` at line 1 column 1\n\
145/// Unexpected: unexpected string at line 2 column 8"
146/// );
147/// ```
148pub struct Error {
149 // boxed so that results stay small. Errors are rare but results are
150 // passed around for every single value.
151 inner: Box<ErrorInner>,
152}
153
154enum ErrorInner {
155 Single(ErrorData),
156 // at least two errors, all of them are single errors. The first one
157 // is the error the accessors refer to.
158 Multiple(Vec<Error>),
159}
160
161#[derive(Debug)]
162struct ErrorData {
163 kind: ErrorKind,
164 msg: Cow<'static, str>,
165 source: Option<Box<dyn core::error::Error + Send + Sync>>,
166 offset: Option<usize>,
167 // line and column (1-based)
168 line_column: Option<(usize, usize)>,
169 // in the order they were attached, at most one per type
170 attachments: Vec<Attachment>,
171 // `true` once the driver attached the context of the current event.
172 has_context: bool,
173 // `true` once the error was collected (see `CollectedErrors`)
174 collected: bool,
175}
176
177#[derive(Debug)]
178struct Attachment {
179 // Invariant: the type of the value
180 type_id: TypeId,
181 value: Box<dyn ErrorAttachment>,
182}
183
184impl Error {
185 /// Creates a new error.
186 #[cold]
187 pub fn new<M: Into<Cow<'static, str>>>(kind: ErrorKind, msg: M) -> Error {
188 Error {
189 inner: Box::new(ErrorInner::Single(ErrorData {
190 kind,
191 msg: msg.into(),
192 source: None,
193 offset: None,
194 line_column: None,
195 attachments: Vec::new(),
196 has_context: false,
197 collected: false,
198 })),
199 }
200 }
201
202 /// Combines errors into one.
203 ///
204 /// Errors that hold multiple errors are flattened (see
205 /// [`push_error`](Self::push_error)). Returns `None` if there are no
206 /// errors.
207 pub fn from_errors<I: IntoIterator<Item = Error>>(errors: I) -> Option<Error> {
208 let mut errors = errors.into_iter();
209 let mut rv = errors.next()?;
210 for err in errors {
211 rv.push_error(err);
212 }
213 Some(rv)
214 }
215
216 /// Creates the error for a value that is serialized while another one
217 /// is only partially written.
218 ///
219 /// Stream serializers return this once they are
220 /// [in progress](crate::ser::StreamSerializer::in_progress) and are asked
221 /// to serialize another value.
222 #[cold]
223 pub fn in_progress() -> Error {
224 Error::new(
225 ErrorKind::Unexpected,
226 "a value was only partially written, the stream cannot continue",
227 )
228 }
229
230 /// Adds an error to this error.
231 ///
232 /// If the error that is added holds multiple errors, they are added
233 /// individually: errors do not nest (see [`errors`](Self::errors)).
234 pub fn push_error(&mut self, err: Error) {
235 let errors = self.make_multiple();
236 match *err.inner {
237 ErrorInner::Single(data) => errors.push(Error {
238 inner: Box::new(ErrorInner::Single(data)),
239 }),
240 ErrorInner::Multiple(others) => errors.extend(others),
241 }
242 }
243
244 /// Turns the error into one that holds multiple errors.
245 fn make_multiple(&mut self) -> &mut Vec<Error> {
246 if let ErrorInner::Single(_) = *self.inner {
247 let first = core::mem::replace(&mut *self.inner, ErrorInner::Multiple(Vec::new()));
248 if let ErrorInner::Multiple(ref mut errors) = *self.inner {
249 errors.push(Error {
250 inner: Box::new(first),
251 });
252 }
253 }
254 match *self.inner {
255 ErrorInner::Multiple(ref mut errors) => errors,
256 ErrorInner::Single(_) => unreachable!(),
257 }
258 }
259
260 /// Iterates over the errors this error holds.
261 ///
262 /// For an error that holds a single error, this is the error itself.
263 /// The errors that are returned hold a single error each.
264 pub fn errors(&self) -> impl Iterator<Item = &Error> {
265 match *self.inner {
266 ErrorInner::Single(_) => core::slice::from_ref(self).iter(),
267 ErrorInner::Multiple(ref errors) => errors.iter(),
268 }
269 }
270
271 /// Returns the number of errors this error holds.
272 pub fn error_count(&self) -> usize {
273 match *self.inner {
274 ErrorInner::Single(_) => 1,
275 ErrorInner::Multiple(ref errors) => errors.len(),
276 }
277 }
278
279 /// Returns the data of the (first) error.
280 fn data(&self) -> &ErrorData {
281 match *self.inner {
282 ErrorInner::Single(ref data) => data,
283 ErrorInner::Multiple(ref errors) => errors[0].data(),
284 }
285 }
286
287 /// Returns the data of the (first) error mutably.
288 fn data_mut(&mut self) -> &mut ErrorData {
289 match *self.inner {
290 ErrorInner::Single(ref mut data) => data,
291 ErrorInner::Multiple(ref mut errors) => errors[0].data_mut(),
292 }
293 }
294
295 /// Applies a function to every error this error holds.
296 pub(crate) fn map_each(mut self, mut f: impl FnMut(Error) -> Error) -> Error {
297 if let ErrorInner::Multiple(ref mut errors) = *self.inner {
298 for err in errors.iter_mut() {
299 let taken = core::mem::replace(err, Error::new(ErrorKind::Unexpected, ""));
300 *err = f(taken);
301 }
302 self
303 } else {
304 f(self)
305 }
306 }
307
308 /// Returns the number of errors this error holds that were not
309 /// collected yet.
310 pub(crate) fn uncollected_count(&self) -> usize {
311 self.errors().filter(|err| !err.data().collected).count()
312 }
313
314 /// Marks all errors this error holds as collected.
315 pub(crate) fn mark_collected(mut self) -> Error {
316 self = self.map_each(|mut err| {
317 err.data_mut().collected = true;
318 err
319 });
320 self
321 }
322
323 /// Attaches another error as source to this error.
324 pub fn with_source<E: core::error::Error + Send + Sync + 'static>(mut self, source: E) -> Self {
325 self.data_mut().source = Some(Box::new(source));
326 self
327 }
328
329 /// Returns the kind of the error.
330 pub fn kind(&self) -> ErrorKind {
331 self.data().kind
332 }
333
334 /// Returns the message of the error (without context).
335 pub fn message(&self) -> &str {
336 &self.data().msg
337 }
338
339 /// Sets the byte offset in the input the error refers to.
340 ///
341 /// A previously set line and column are discarded.
342 pub fn with_offset(mut self, offset: usize) -> Self {
343 let data = self.data_mut();
344 data.offset = Some(offset);
345 data.line_column = None;
346 self
347 }
348
349 /// Sets the byte offset together with its line and column (1-based).
350 pub fn with_position(mut self, offset: usize, line: usize, column: usize) -> Self {
351 let data = self.data_mut();
352 data.offset = Some(offset);
353 data.line_column = Some((line, column));
354 self
355 }
356
357 /// Resolves the offset into line and column.
358 ///
359 /// The source is the input the offset refers to. Columns are counted
360 /// in characters (bytes that are not UTF-8 continuation bytes). If the
361 /// error has no offset or already has a line and column, it's returned
362 /// unchanged. Text formats call this for the errors they return.
363 ///
364 /// ```
365 /// use deser::{Error, ErrorKind};
366 ///
367 /// let err = Error::new(ErrorKind::Unexpected, "bad value")
368 /// .with_offset(7)
369 /// .resolve_position(b"[1,\n x]");
370 /// assert_eq!((err.line(), err.column()), (Some(2), Some(4)));
371 /// ```
372 ///
373 /// The positions of further errors (see [`errors`](Self::errors)) are
374 /// resolved as well.
375 pub fn resolve_position(self, source: &[u8]) -> Self {
376 self.map_each(|mut err| {
377 let data = err.data_mut();
378 if let (Some(offset), None) = (data.offset, data.line_column) {
379 let pos = Position::of(source, offset);
380 data.line_column = Some((pos.line, pos.column));
381 }
382 err
383 })
384 }
385
386 /// Moves the position of the error by the position of the input it
387 /// refers to.
388 ///
389 /// This is used for errors of inputs which are part of a larger input,
390 /// the base is the position of the start of the part.
391 pub(crate) fn shift_position(self, base: Position) -> Self {
392 self.map_each(|mut err| {
393 let data = err.data_mut();
394 if let Some(ref mut error_offset) = data.offset {
395 *error_offset += base.offset;
396 }
397 if let Some((ref mut error_line, ref mut error_column)) = data.line_column {
398 if *error_line == 1 {
399 *error_column += base.column - 1;
400 }
401 *error_line += base.line - 1;
402 }
403 err
404 })
405 }
406
407 /// Returns the byte offset in the input the error refers to.
408 pub fn offset(&self) -> Option<usize> {
409 self.data().offset
410 }
411
412 /// Returns the line (1-based) the error refers to.
413 pub fn line(&self) -> Option<usize> {
414 self.data().line_column.map(|x| x.0)
415 }
416
417 /// Returns the column (1-based, in characters) the error refers to.
418 pub fn column(&self) -> Option<usize> {
419 self.data().line_column.map(|x| x.1)
420 }
421
422 /// Attaches a value to the error.
423 ///
424 /// An attachment of the same type is replaced but keeps its position
425 /// in the [`Display`](fmt::Display) output. See [`ErrorAttachment`].
426 pub fn with_attachment<T: ErrorAttachment>(mut self, value: T) -> Self {
427 let type_id = TypeId::of::<T>();
428 let value = Box::new(value);
429 let attachments = &mut self.data_mut().attachments;
430 match attachments.iter_mut().find(|x| x.type_id == type_id) {
431 Some(attachment) => attachment.value = value,
432 None => attachments.push(Attachment { type_id, value }),
433 }
434 self
435 }
436
437 /// Returns the attachment of the given type.
438 pub fn attachment<T: ErrorAttachment>(&self) -> Option<&T> {
439 let type_id = TypeId::of::<T>();
440 let attachment = self
441 .data()
442 .attachments
443 .iter()
444 .find(|x| x.type_id == type_id)?;
445 (&*attachment.value as &dyn Any).downcast_ref()
446 }
447
448 /// Returns the attachment of the given type mutably.
449 pub fn attachment_mut<T: ErrorAttachment>(&mut self) -> Option<&mut T> {
450 let type_id = TypeId::of::<T>();
451 let attachment = self
452 .data_mut()
453 .attachments
454 .iter_mut()
455 .find(|x| x.type_id == type_id)?;
456 (&mut *attachment.value as &mut dyn Any).downcast_mut()
457 }
458
459 /// Iterates over the attachments in the order they were attached.
460 pub fn attachments(&self) -> impl Iterator<Item = &dyn ErrorAttachment> {
461 self.data().attachments.iter().map(|x| &*x.value)
462 }
463
464 /// Returns `true` if the context of an event was attached.
465 pub(crate) fn has_context(&self) -> bool {
466 self.data().has_context
467 }
468
469 /// Marks the context of an event as attached.
470 pub(crate) fn set_has_context(&mut self) {
471 self.data_mut().has_context = true;
472 }
473}
474
475impl fmt::Debug for Error {
476 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477 let data = match *self.inner {
478 ErrorInner::Single(ref data) => data,
479 ErrorInner::Multiple(ref errors) => {
480 return f.debug_tuple("Errors").field(errors).finish();
481 }
482 };
483 let mut s = f.debug_struct("Error");
484 s.field("kind", &data.kind).field("msg", &data.msg);
485 if let Some(offset) = data.offset {
486 s.field("offset", &offset);
487 }
488 if let Some((line, column)) = data.line_column {
489 s.field("line", &line).field("column", &column);
490 }
491 if !data.attachments.is_empty() {
492 s.field("attachments", &DebugAttachments(&data.attachments));
493 }
494 s.field("source", &data.source).finish()
495 }
496}
497
498impl ErrorData {
499 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
500 write!(f, "{:?}: {}", self.kind, self.msg)?;
501 match (self.line_column, self.offset) {
502 (Some((line, column)), _) => write!(f, " at line {} column {}", line, column)?,
503 (None, Some(offset)) => write!(f, " at offset {}", offset)?,
504 (None, None) => {}
505 }
506 for attachment in self.attachments.iter() {
507 attachment.value.fmt_context(f)?;
508 }
509 Ok(())
510 }
511}
512
513impl fmt::Display for Error {
514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
515 let errors = match *self.inner {
516 ErrorInner::Single(ref data) => return data.fmt(f),
517 ErrorInner::Multiple(ref errors) => errors,
518 };
519 errors[0].data().fmt(f)?;
520 if f.alternate() {
521 for err in &errors[1..] {
522 writeln!(f)?;
523 err.data().fmt(f)?;
524 }
525 } else if errors.len() == 2 {
526 write!(f, " (and 1 more error)")?;
527 } else {
528 write!(f, " (and {} more errors)", errors.len() - 1)?;
529 }
530 Ok(())
531 }
532}
533
534struct DebugAttachments<'a>(&'a [Attachment]);
535
536impl fmt::Debug for DebugAttachments<'_> {
537 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
538 f.debug_list()
539 .entries(self.0.iter().map(|x| &x.value))
540 .finish()
541 }
542}
543
544#[cfg(feature = "std")]
545impl From<std::io::Error> for Error {
546 fn from(err: std::io::Error) -> Error {
547 Error::new(ErrorKind::Io, err.to_string()).with_source(err)
548 }
549}
550
551impl core::error::Error for Error {
552 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
553 self.data().source.as_ref().map(|err| err.as_ref() as _)
554 }
555}
556
557/// Creates an error that is thrown away.
558///
559/// While errors are discarded (see `State::discard_errors`) the common
560/// errors are created with this instead of building a message nobody reads.
561#[cold]
562#[inline(never)]
563pub(crate) fn discarded_error(kind: ErrorKind) -> Error {
564 Error::new(kind, "discarded error")
565}
566
567/// Creates the error for a value that failed to convert or validate.
568#[cold]
569pub(crate) fn conversion_error<E: fmt::Display>(err: E) -> Error {
570 Error::new(ErrorKind::Unexpected, format!("invalid value: {}", err))
571}
572
573/// Creates the error for an unknown variant.
574///
575/// `tag` is the name that was given (if it can be a name), `type_name` the
576/// name of the enum and `names` are the names of the variants.
577#[cold]
578pub fn unknown_variant(tag: Option<&str>, type_name: &str, names: &[&str]) -> Error {
579 let mut msg = String::from("unknown variant");
580 if let Some(tag) = tag {
581 msg.push_str(" `");
582 msg.push_str(tag);
583 msg.push('`');
584 }
585 msg.push_str(" of ");
586 msg.push_str(type_name);
587 push_expected(&mut msg, names, "variants");
588 Error::new(ErrorKind::Unexpected, msg)
589}
590
591/// Appends the expected names to an error message.
592///
593/// `what` is what the names are, for the message if there are none.
594pub(crate) fn push_expected(msg: &mut String, names: &[&str], what: &str) {
595 match names {
596 [] => {
597 msg.push_str(", there are no ");
598 msg.push_str(what);
599 }
600 [name] => {
601 msg.push_str(", expected `");
602 msg.push_str(name);
603 msg.push('`');
604 }
605 [first, second] => {
606 msg.push_str(", expected `");
607 msg.push_str(first);
608 msg.push_str("` or `");
609 msg.push_str(second);
610 msg.push('`');
611 }
612 names => {
613 msg.push_str(", expected one of ");
614 for (idx, name) in names.iter().enumerate() {
615 if idx > 0 {
616 msg.push_str(", ");
617 }
618 msg.push('`');
619 msg.push_str(name);
620 msg.push('`');
621 }
622 }
623 }
624}