Skip to main content

docspec_core/
error.rs

1//! Error types for `DocSpec` operations.
2
3use core::fmt;
4
5use thiserror::Error;
6
7/// The position in a source document where an error occurred.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Position {
10    /// Byte offset from the start of the input.
11    pub byte_offset: usize,
12    /// Column number (1-based), if available.
13    pub column: Option<usize>,
14    /// Line number (1-based), if available.
15    pub line: Option<usize>,
16}
17
18/// Errors that can occur during document processing.
19#[derive(Debug, Error)]
20#[non_exhaustive]
21pub enum Error {
22    /// An event sequence violated the well-formedness rules.
23    #[error("invalid event sequence: expected {expected}, found {found}: {message}")]
24    InvalidSequence {
25        /// The event type that was expected.
26        expected: String,
27        /// The event type that was actually found.
28        found: String,
29        /// Human-readable description.
30        message: String,
31    },
32    /// An I/O error from the underlying reader or writer.
33    #[error("I/O error: {source}")]
34    Io {
35        /// The underlying I/O error.
36        #[from]
37        source: std::io::Error,
38    },
39    /// A JSON parse or serialization error.
40    #[error("{}", DisplayPos { label: "JSON error", message: message.as_str(), position: position.as_ref() })]
41    Json {
42        /// Human-readable description.
43        message: String,
44        /// Position in the JSON source, if known.
45        position: Option<Position>,
46    },
47    /// An unclassified error.
48    #[error("{message}")]
49    Other {
50        /// Human-readable description.
51        message: String,
52    },
53    /// A parse error, optionally with position information.
54    #[error("{}", DisplayPos { label: "parse error", message: message.as_str(), position: position.as_ref() })]
55    Parse {
56        /// Human-readable description of what went wrong.
57        message: String,
58        /// Position in the source where the error occurred, if known.
59        position: Option<Position>,
60    },
61}
62
63/// Result type alias for `DocSpec` operations.
64pub type Result<T> = core::result::Result<T, Error>;
65
66struct DisplayPos<'a> {
67    label: &'a str,
68    message: &'a str,
69    position: Option<&'a Position>,
70}
71
72impl fmt::Display for DisplayPos<'_> {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        write!(f, "{}", self.label)?;
75        if let Some(pos) = self.position {
76            let byte = pos.byte_offset;
77            match (pos.line, pos.column) {
78                (Some(line), Some(col)) => {
79                    write!(f, " at line {line}, column {col} (byte {byte})")?;
80                }
81                (Some(line), _) => {
82                    write!(f, " at line {line} (byte {byte})")?;
83                }
84                _ => {
85                    write!(f, " at byte {byte}")?;
86                }
87            }
88        }
89        write!(f, ": {}", self.message)
90    }
91}