json5/
error.rs

1use pest::Span;
2use serde::{de, ser};
3use std::fmt::{self, Display};
4
5use crate::de::Rule;
6
7/// Alias for a `Result` with error type `json5::Error`
8pub type Result<T> = std::result::Result<T, Error>;
9
10/// One-based line and column at which the error was detected.
11#[derive(Clone, Debug, PartialEq)]
12pub struct Location {
13    /// The one-based line number of the error.
14    pub line: usize,
15    /// The one-based column number of the error.
16    pub column: usize,
17}
18
19impl From<&Span<'_>> for Location {
20    fn from(s: &Span<'_>) -> Self {
21        let (line, column) = s.start_pos().line_col();
22        Self { line, column }
23    }
24}
25
26/// A bare bones error type which currently just collapses all the underlying errors in to a single
27/// string... This is fine for displaying to the user, but not very useful otherwise. Work to be
28/// done here.
29#[derive(Clone, Debug, PartialEq)]
30pub enum Error {
31    /// Just shove everything in a single variant for now.
32    Message {
33        /// The error message.
34        msg: String,
35        /// The location of the error, if applicable.
36        location: Option<Location>,
37    },
38}
39
40impl From<pest::error::Error<Rule>> for Error {
41    fn from(err: pest::error::Error<Rule>) -> Self {
42        let (line, column) = match err.line_col {
43            pest::error::LineColLocation::Pos((l, c)) => (l, c),
44            pest::error::LineColLocation::Span((l, c), (_, _)) => (l, c),
45        };
46        Error::Message {
47            msg: err.to_string(),
48            location: Some(Location { line, column }),
49        }
50    }
51}
52
53impl ser::Error for Error {
54    fn custom<T: Display>(msg: T) -> Self {
55        Error::Message {
56            msg: msg.to_string(),
57            location: None,
58        }
59    }
60}
61
62impl de::Error for Error {
63    fn custom<T: Display>(msg: T) -> Self {
64        Error::Message {
65            msg: msg.to_string(),
66            location: None,
67        }
68    }
69}
70
71impl Display for Error {
72    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
73        match self {
74            Error::Message { ref msg, .. } => write!(formatter, "{}", msg),
75        }
76    }
77}
78
79impl std::error::Error for Error {}
80
81/// Adds location information from `span`, if `res` is an error.
82pub fn set_location<T>(res: &mut Result<T>, span: &Span<'_>) {
83    if let Err(ref mut e) = res {
84        let Error::Message { location, .. } = e;
85        if location.is_none() {
86            let (line, column) = span.start_pos().line_col();
87            *location = Some(Location { line, column });
88        }
89    }
90}