Skip to main content

tjson/
error.rs

1use std::error::Error as StdError;
2use std::fmt;
3
4/// A parse error with source location and optional source line context.
5///
6/// The `Display` implementation formats the error as `line N, column M: message` and,
7/// when source context is available, appends the source line and a caret pointer.
8#[derive(Clone, Debug, PartialEq, Eq)]
9#[non_exhaustive]
10pub struct ParseError {
11    line: usize,
12    column: usize,
13    message: String,
14    source_line: Option<String>,
15}
16
17impl ParseError {
18    pub(crate) fn new(line: usize, column: usize, message: impl Into<String>, source_line: Option<String>) -> Self {
19        Self {
20            line,
21            column,
22            message: message.into(),
23            source_line,
24        }
25    }
26
27    /// 1-based line number where the error occurred.
28    pub fn line(&self) -> usize { self.line }
29    /// 1-based column number where the error occurred.
30    pub fn column(&self) -> usize { self.column }
31    /// Human-readable error message.
32    pub fn message(&self) -> &str { &self.message }
33    /// The source line text, if available, for display with a caret pointer.
34    pub fn source_line(&self) -> Option<&str> { self.source_line.as_deref() }
35}
36
37impl fmt::Display for ParseError {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        write!(f, "line {}, column {}: {}", self.line, self.column, self.message)?;
40        if let Some(src) = &self.source_line {
41            write!(f, "\n  {}\n  {:>width$}", src, "^", width = self.column)?;
42        }
43        Ok(())
44    }
45}
46
47impl StdError for ParseError {}
48
49/// The error type for all TJSON operations.
50#[non_exhaustive]
51#[derive(Debug)]
52pub enum Error {
53    /// A parse error with source location.
54    Parse(ParseError),
55    /// A JSON serialization or deserialization error from serde_json.
56    Json(serde_json::Error),
57    /// A render error due to an internal invariant violation (indicates a bug in this library).
58    Render(String),
59}
60
61impl fmt::Display for Error {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        match self {
64            Self::Parse(error) => write!(f, "{error}"),
65            Self::Json(error) => write!(f, "{error}"),
66            Self::Render(message) => write!(f, "{message}"),
67        }
68    }
69}
70
71impl StdError for Error {}
72
73impl From<ParseError> for Error {
74    fn from(error: ParseError) -> Self {
75        Self::Parse(error)
76    }
77}
78
79impl From<serde_json::Error> for Error {
80    fn from(error: serde_json::Error) -> Self {
81        Self::Json(error)
82    }
83}
84
85/// Convenience `Result` type with [`Error`] as the default error type.
86pub type Result<T, E = Error> = std::result::Result<T, E>;