1use std::fmt::{Display, Formatter};
2
3pub type Result<T> = std::result::Result<T, Error>;
4
5#[derive(Debug, PartialEq, Clone)]
7pub struct Error {
8 inner: Box<ErrorInner>,
9}
10
11impl Error {
12 #[must_use]
13 pub fn code(&self) -> Option<ErrorCode> {
14 match self.inner.content {
15 ErrorContent::Code(code) => Some(code),
16 ErrorContent::Custom(_) => None,
17 }
18 }
19
20 #[must_use]
21 pub fn position(&self) -> Option<Position> {
22 self.inner.position
23 }
24}
25
26#[derive(Debug, PartialEq, Clone)]
27struct ErrorInner {
28 content: ErrorContent,
29 position: Option<Position>,
30}
31
32#[derive(Debug, PartialEq, Clone)]
33enum ErrorContent {
34 Code(ErrorCode),
35 Custom(String),
36}
37
38#[derive(Debug, PartialEq, Clone, Copy)]
40pub enum ErrorCode {
41 EofParsingArray,
42 EofParsingBool,
43 EofParsingComment,
44 EofParsingEscapeSequence,
45 EofParsingIdentifier,
46 EofParsingNull,
47 EofParsingNumber,
48 EofParsingObject,
49 EofParsingString,
50 EofParsingValue,
51
52 ExpectedBool,
53 ExpectedClosingBrace,
54 ExpectedClosingBracket,
55 ExpectedColon,
56 ExpectedComma,
57 ExpectedComment,
58 ExpectedIdentifier,
59 ExpectedNull,
60 ExpectedNumber,
61 ExpectedOpeningBrace,
62 ExpectedOpeningBracket,
63 ExpectedString,
64 ExpectedStringOrObject,
65 ExpectedValue,
66
67 InvalidBytes,
68 InvalidEscapeSequence,
69 InvalidKey,
70 LeadingZero,
71 LineTerminatorInString,
72 OverflowParsingNumber,
73 TrailingCharacters,
74}
75
76impl Display for ErrorCode {
77 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
78 match self {
79 ErrorCode::EofParsingArray => write!(f, "EOF parsing array"),
80 ErrorCode::EofParsingBool => write!(f, "EOF parsing bool"),
81 ErrorCode::EofParsingComment => write!(f, "EOF parsing comment"),
82 ErrorCode::EofParsingEscapeSequence => write!(f, "EOF parsing escape sequence"),
83 ErrorCode::EofParsingIdentifier => write!(f, "EOF parsing identifier"),
84 ErrorCode::EofParsingNull => write!(f, "EOF parsing null"),
85 ErrorCode::EofParsingNumber => write!(f, "EOF parsing number"),
86 ErrorCode::EofParsingObject => write!(f, "EOF parsing object"),
87 ErrorCode::EofParsingString => write!(f, "EOF parsing string"),
88 ErrorCode::EofParsingValue => write!(f, "EOF parsing value"),
89
90 ErrorCode::ExpectedBool => write!(f, "expected bool"),
91 ErrorCode::ExpectedClosingBrace => write!(f, "expected closing brace"),
92 ErrorCode::ExpectedClosingBracket => write!(f, "expected closing bracket"),
93 ErrorCode::ExpectedColon => write!(f, "expected colon"),
94 ErrorCode::ExpectedComma => write!(f, "expected comma"),
95 ErrorCode::ExpectedComment => write!(f, "expected comment"),
96 ErrorCode::ExpectedIdentifier => write!(f, "expected identifier"),
97 ErrorCode::ExpectedNull => write!(f, "expected null"),
98 ErrorCode::ExpectedNumber => write!(f, "expected number"),
99 ErrorCode::ExpectedOpeningBrace => write!(f, "expected opening brace"),
100 ErrorCode::ExpectedOpeningBracket => write!(f, "expected opening bracket"),
101 ErrorCode::ExpectedString => write!(f, "expected string"),
102 ErrorCode::ExpectedStringOrObject => write!(f, "expected string or object"),
103 ErrorCode::ExpectedValue => write!(f, "expected value"),
104
105 ErrorCode::InvalidBytes => write!(f, "invalid bytes"),
106 ErrorCode::InvalidEscapeSequence => write!(f, "invalid escape sequence"),
107 ErrorCode::InvalidKey => write!(f, "invalid key"),
108 ErrorCode::LeadingZero => write!(f, "leading zero"),
109 ErrorCode::LineTerminatorInString => write!(f, "line terminator in string"),
110 ErrorCode::OverflowParsingNumber => write!(f, "overflow parsing number"),
111 ErrorCode::TrailingCharacters => write!(f, "trailing characters"),
112 }
113 }
114}
115
116impl Display for ErrorContent {
117 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
118 match self {
119 ErrorContent::Code(code) => write!(f, "{code}"),
120 ErrorContent::Custom(msg) => write!(f, "{msg}"),
121 }
122 }
123}
124
125impl Display for Error {
126 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
127 if let Some(position) = self.inner.position {
128 write!(f, "{} at {}", self.inner.content, position)
129 } else {
130 write!(f, "{}", self.inner.content)
131 }
132 }
133}
134
135impl Error {
136 #[must_use]
137 pub fn new(code: ErrorCode) -> Self {
138 Self {
139 inner: Box::new(ErrorInner {
140 content: ErrorContent::Code(code),
141 position: None,
142 }),
143 }
144 }
145
146 #[must_use]
147 pub fn new_at(position: Position, code: ErrorCode) -> Self {
148 Self {
149 inner: Box::new(ErrorInner {
150 content: ErrorContent::Code(code),
151 position: Some(position),
152 }),
153 }
154 }
155
156 #[must_use]
157 pub fn custom<T: Display>(msg: T) -> Self {
158 Self {
159 inner: Box::new(ErrorInner {
160 content: ErrorContent::Custom(msg.to_string()),
161 position: None,
162 }),
163 }
164 }
165
166 #[must_use]
167 pub fn custom_at<T: Display>(position: Position, msg: T) -> Self {
168 Self {
169 inner: Box::new(ErrorInner {
170 content: ErrorContent::Custom(msg.to_string()),
171 position: Some(position),
172 }),
173 }
174 }
175
176 #[must_use]
177 pub fn with_position(mut self, position: Position) -> Self {
178 if self.inner.position.is_none() {
179 self.inner.position = Some(position);
180 }
181 self
182 }
183}
184
185impl serde::de::Error for Error {
186 fn custom<T: Display>(msg: T) -> Self {
187 Self::custom(msg)
188 }
189}
190
191impl serde::ser::Error for Error {
192 fn custom<T: Display>(msg: T) -> Self {
193 Self::custom(msg)
194 }
195}
196
197impl From<std::io::Error> for Error {
198 fn from(err: std::io::Error) -> Self {
199 Self::custom(err)
200 }
201}
202
203impl std::error::Error for Error {}
204
205#[derive(Debug, PartialEq, Clone, Copy)]
207pub struct Position {
208 pub line: usize,
210 pub column: usize,
212}
213
214impl Position {
215 #[must_use]
216 pub fn from_offset(offset: usize, input: &str) -> Self {
217 let mut res = Self { line: 0, column: 0 };
218 let mut chars = input[..offset].chars().peekable();
219 while let Some(c) = chars.next() {
220 if crate::char::is_json5_line_terminator(c) {
221 if c == '\u{000D}' && chars.peek() == Some(&'\u{000A}') {
225 chars.next();
226 }
227 res.line += 1;
228 res.column = 0;
229 } else {
230 res.column += 1;
231 }
232 }
233 res
234 }
235}
236
237impl Display for Position {
238 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
239 write!(f, "line {} column {}", self.line + 1, self.column + 1)
240 }
241}