-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
errors.rs
293 lines (244 loc) · 9.13 KB
/
errors.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/// Enum representing all possible errors in JSON syntax.
///
/// Almost all of `JsonErrorType` is copied from [serde_json](https://github.com/serde-rs) so errors match
/// those expected from `serde_json`.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum JsonErrorType {
/// float value was found where an int was expected
FloatExpectingInt,
/// duplicate keys in an object
DuplicateKey(String),
/// NOTE: all errors from here on are copied from serde_json
/// [src/error.rs](https://github.com/serde-rs/json/blob/v1.0.107/src/error.rs#L236)
/// with `Io` and `Message` removed
///
/// EOF while parsing a list.
EofWhileParsingList,
/// EOF while parsing an object.
EofWhileParsingObject,
/// EOF while parsing a string.
EofWhileParsingString,
/// EOF while parsing a JSON value.
EofWhileParsingValue,
/// Expected this character to be a `':'`.
ExpectedColon,
/// Expected this character to be either a `','` or a `']'`.
ExpectedListCommaOrEnd,
/// Expected this character to be either a `','` or a `'}'`.
ExpectedObjectCommaOrEnd,
/// Expected to parse either a `true`, `false`, or a `null`.
ExpectedSomeIdent,
/// Expected this character to start a JSON value.
ExpectedSomeValue,
/// Invalid hex escape code.
InvalidEscape,
/// Invalid number.
InvalidNumber,
/// Number is bigger than the maximum value of its type.
NumberOutOfRange,
/// Invalid unicode code point.
InvalidUnicodeCodePoint,
/// Control character found while parsing a string.
ControlCharacterWhileParsingString,
/// Object key is not a string.
KeyMustBeAString,
/// Lone leading surrogate in hex escape.
LoneLeadingSurrogateInHexEscape,
/// JSON has a comma after the last value in an array or map.
TrailingComma,
/// JSON has non-whitespace trailing characters after the value.
TrailingCharacters,
/// Unexpected end of hex escape.
UnexpectedEndOfHexEscape,
/// Encountered nesting of JSON maps and arrays more than 128 layers deep.
RecursionLimitExceeded,
}
impl std::fmt::Display for JsonErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Messages for enum members copied from serde_json are unchanged
match self {
Self::FloatExpectingInt => f.write_str("float value was found where an int was expected"),
Self::DuplicateKey(s) => write!(f, "Detected duplicate key {s:?}"),
Self::EofWhileParsingList => f.write_str("EOF while parsing a list"),
Self::EofWhileParsingObject => f.write_str("EOF while parsing an object"),
Self::EofWhileParsingString => f.write_str("EOF while parsing a string"),
Self::EofWhileParsingValue => f.write_str("EOF while parsing a value"),
Self::ExpectedColon => f.write_str("expected `:`"),
Self::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"),
Self::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"),
Self::ExpectedSomeIdent => f.write_str("expected ident"),
Self::ExpectedSomeValue => f.write_str("expected value"),
Self::InvalidEscape => f.write_str("invalid escape"),
Self::InvalidNumber => f.write_str("invalid number"),
Self::NumberOutOfRange => f.write_str("number out of range"),
Self::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
Self::ControlCharacterWhileParsingString => {
f.write_str("control character (\\u0000-\\u001F) found while parsing a string")
}
Self::KeyMustBeAString => f.write_str("key must be a string"),
Self::LoneLeadingSurrogateInHexEscape => f.write_str("lone leading surrogate in hex escape"),
Self::TrailingComma => f.write_str("trailing comma"),
Self::TrailingCharacters => f.write_str("trailing characters"),
Self::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"),
Self::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
}
}
}
pub type JsonResult<T> = Result<T, JsonError>;
/// Represents an error from parsing JSON
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct JsonError {
/// The type of error.
pub error_type: JsonErrorType,
/// The index in the data where the error occurred.
pub index: usize,
}
impl JsonError {
pub(crate) fn new(error_type: JsonErrorType, index: usize) -> Self {
Self { error_type, index }
}
pub fn get_position(&self, json_data: &[u8]) -> LinePosition {
LinePosition::find(json_data, self.index)
}
pub fn description(&self, json_data: &[u8]) -> String {
let position = self.get_position(json_data);
format!("{} at {}", self.error_type, position)
}
}
impl std::fmt::Display for JsonError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} at index {}", self.error_type, self.index)
}
}
macro_rules! json_error {
($error_type:ident, $index:expr) => {
crate::errors::JsonError::new(crate::errors::JsonErrorType::$error_type, $index)
};
}
pub(crate) use json_error;
macro_rules! json_err {
($error_type:ident, $index:expr) => {
Err(crate::errors::json_error!($error_type, $index))
};
}
use crate::Jiter;
pub(crate) use json_err;
pub(crate) const DEFAULT_RECURSION_LIMIT: u8 = 200;
/// Enum representing all JSON types.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum JsonType {
Null,
Bool,
Int,
Float,
String,
Array,
Object,
}
impl std::fmt::Display for JsonType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Null => f.write_str("null"),
Self::Bool => f.write_str("bool"),
Self::Int => f.write_str("int"),
Self::Float => f.write_str("float"),
Self::String => f.write_str("string"),
Self::Array => f.write_str("array"),
Self::Object => f.write_str("object"),
}
}
}
/// Enum representing either a [JsonErrorType] or a WrongType error.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum JiterErrorType {
JsonError(JsonErrorType),
WrongType { expected: JsonType, actual: JsonType },
}
impl std::fmt::Display for JiterErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::JsonError(error_type) => write!(f, "{error_type}"),
Self::WrongType { expected, actual } => {
write!(f, "expected {expected} but found {actual}")
}
}
}
}
/// An error from the Jiter iterator.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct JiterError {
pub error_type: JiterErrorType,
pub index: usize,
}
impl std::fmt::Display for JiterError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} at index {}", self.error_type, self.index)
}
}
impl JiterError {
pub(crate) fn new(error_type: JiterErrorType, index: usize) -> Self {
Self { error_type, index }
}
pub fn get_position(&self, jiter: &Jiter) -> LinePosition {
jiter.error_position(self.index)
}
pub fn description(&self, jiter: &Jiter) -> String {
let position = self.get_position(jiter);
format!("{} at {}", self.error_type, position)
}
pub(crate) fn wrong_type(expected: JsonType, actual: JsonType, index: usize) -> Self {
Self::new(JiterErrorType::WrongType { expected, actual }, index)
}
}
impl From<JsonError> for JiterError {
fn from(error: JsonError) -> Self {
Self {
error_type: JiterErrorType::JsonError(error.error_type),
index: error.index,
}
}
}
/// Represents a line and column in a file or input string, used for both errors and value positions.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LinePosition {
/// Line number, starting at 1.
pub line: usize,
/// Column number, starting at 1.
pub column: usize,
}
impl std::fmt::Display for LinePosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "line {} column {}", self.line, self.column)
}
}
impl LinePosition {
pub fn new(line: usize, column: usize) -> Self {
Self { line, column }
}
/// Find the line and column of a byte index in a string.
pub fn find(json_data: &[u8], find: usize) -> Self {
let mut line = 1;
let mut last_line_start = 0;
let mut index = 0;
while let Some(next) = json_data.get(index) {
if *next == b'\n' {
line += 1;
last_line_start = index + 1;
}
if index == find {
return Self {
line,
column: index + 1 - last_line_start,
};
}
index += 1;
}
Self {
line,
column: index.saturating_sub(last_line_start),
}
}
pub fn short(&self) -> String {
format!("{}:{}", self.line, self.column)
}
}