simd_json/
error.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
use std::fmt;

use value_trait::ValueType;

/// Error types encountered while parsing
#[derive(Debug)]
pub enum ErrorType {
    /// A specific type was expected but another one encountered.
    Unexpected(Option<ValueType>, Option<ValueType>),
    /// Simd-json only supports inputs of up to
    /// 4GB in size.
    InputTooLarge,
    /// The key of a map isn't a string
    BadKeyType,
    /// Expected an array
    ExpectedArray,
    /// Expected a `,` in an array
    ExpectedArrayComma,
    /// expected an boolean
    ExpectedBoolean,
    /// Expected an enum
    ExpectedEnum,
    /// Expected a float
    ExpectedFloat,
    /// Expected an integer
    ExpectedInteger,
    /// Expected a map
    ExpectedMap,
    /// Expected an `:` to separate key and value in an object
    ExpectedObjectColon,
    /// Expected a `,` in an object
    ExpectedMapComma,
    /// Expected the object to end
    ExpectedMapEnd,
    /// Expected a null
    ExpectedNull,
    /// Expected a true
    ExpectedTrue,
    /// Expected a false
    ExpectedFalse,
    /// Expected a number
    ExpectedNumber,
    /// Expected a signed number
    ExpectedSigned,
    /// Expected a string
    ExpectedString,
    /// Expected an unsigned number
    ExpectedUnsigned,
    /// Internal error
    InternalError(InternalError),
    /// Invalid escape sequence
    InvalidEscape,
    /// Invalid exponent in a floating point number
    InvalidExponent,
    /// Invalid number
    InvalidNumber,
    /// Invalid UTF8 codepoint
    InvalidUtf8,
    /// Invalid Unicode escape sequence
    InvalidUnicodeEscape,
    /// Invalid Unicode codepoint
    InvalidUnicodeCodepoint,
    /// Object Key isn't a string
    KeyMustBeAString,
    /// Non structural character
    NoStructure,
    /// Parser Error
    Parser,
    /// Early End Of File
    Eof,
    /// Generic serde error
    Serde(String),
    /// Generic syntax error
    Syntax,
    /// Trailing data
    TrailingData,
    /// Unexpected character
    UnexpectedCharacter,
    /// Unterminated string
    UnterminatedString,
    /// Expected Array elements
    ExpectedArrayContent,
    /// Expected Object elements
    ExpectedObjectContent,
    /// Expected Object Key
    ExpectedObjectKey,
    /// Overflow of a limited buffer
    Overflow,
    /// No SIMD support detected during runtime
    SimdUnsupported,
    /// IO error
    Io(std::io::Error),
}

#[derive(Clone, Debug, PartialEq)]
pub enum InternalError {
    TapeError,
}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Self {
        Self::generic(ErrorType::Io(e))
    }
}

#[cfg(not(tarpaulin_include))]
impl PartialEq for ErrorType {
    #[must_use]
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::Io(_), Self::Io(_))
            | (Self::BadKeyType, Self::BadKeyType)
            | (Self::ExpectedArray, Self::ExpectedArray)
            | (Self::ExpectedArrayComma, Self::ExpectedArrayComma)
            | (Self::ExpectedBoolean, Self::ExpectedBoolean)
            | (Self::ExpectedTrue, Self::ExpectedTrue)
            | (Self::ExpectedFalse, Self::ExpectedFalse)
            | (Self::ExpectedEnum, Self::ExpectedEnum)
            | (Self::ExpectedFloat, Self::ExpectedFloat)
            | (Self::ExpectedInteger, Self::ExpectedInteger)
            | (Self::ExpectedMap, Self::ExpectedMap)
            | (Self::ExpectedObjectColon, Self::ExpectedObjectColon)
            | (Self::ExpectedMapComma, Self::ExpectedMapComma)
            | (Self::ExpectedMapEnd, Self::ExpectedMapEnd)
            | (Self::ExpectedNull, Self::ExpectedNull)
            | (Self::ExpectedNumber, Self::ExpectedNumber)
            | (Self::ExpectedSigned, Self::ExpectedSigned)
            | (Self::ExpectedString, Self::ExpectedString)
            | (Self::ExpectedUnsigned, Self::ExpectedUnsigned)
            | (Self::InvalidEscape, Self::InvalidEscape)
            | (Self::InvalidExponent, Self::InvalidExponent)
            | (Self::InvalidNumber, Self::InvalidNumber)
            | (Self::InvalidUtf8, Self::InvalidUtf8)
            | (Self::InvalidUnicodeEscape, Self::InvalidUnicodeEscape)
            | (Self::InvalidUnicodeCodepoint, Self::InvalidUnicodeCodepoint)
            | (Self::KeyMustBeAString, Self::KeyMustBeAString)
            | (Self::NoStructure, Self::NoStructure)
            | (Self::Parser, Self::Parser)
            | (Self::Eof, Self::Eof)
            | (Self::Syntax, Self::Syntax)
            | (Self::TrailingData, Self::TrailingData)
            | (Self::UnexpectedCharacter, Self::UnexpectedCharacter)
            | (Self::UnterminatedString, Self::UnterminatedString)
            | (Self::ExpectedArrayContent, Self::ExpectedArrayContent)
            | (Self::ExpectedObjectContent, Self::ExpectedObjectContent)
            | (Self::ExpectedObjectKey, Self::ExpectedObjectKey)
            | (Self::Overflow, Self::Overflow) => true,
            (Self::Serde(s1), Self::Serde(s2)) => s1 == s2,
            (Self::InternalError(e1), Self::InternalError(e2)) => e1 == e2,
            _ => false,
        }
    }
}
/// Parser error
#[derive(Debug, PartialEq)]
pub struct Error {
    /// Byte index it was encountered at
    index: usize,
    /// Current character
    character: Option<char>,
    /// Type of error
    error: ErrorType,
}

impl Error {
    pub(crate) fn new(index: usize, character: Option<char>, error: ErrorType) -> Self {
        Self {
            index,
            character,
            error,
        }
    }
    pub(crate) fn new_c(index: usize, character: char, error: ErrorType) -> Self {
        Self::new(index, Some(character), error)
    }

    /// Create a generic error
    #[must_use = "Error creation"]
    pub fn generic(t: ErrorType) -> Self {
        Self {
            index: 0,
            character: None,
            error: t,
        }
    }

    /// Returns the byte index the error occurred at.
    #[must_use]
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the current character the error occurred at.
    #[must_use]
    pub fn character(&self) -> Option<char> {
        self.character
    }

    /// Returns the type of error that occurred.
    #[must_use]
    pub fn error(&self) -> &ErrorType {
        &self.error
    }

    // These make it a bit easier to fit into a serde_json context
    // The classification is based on that of serde_json - so if maybe
    // you disagree with that classification, please leave as is anyway.

    /// Indicates if the error that occurred was an IO error
    #[must_use]
    pub fn is_io(&self) -> bool {
        // We have to include InternalError _somewhere_
        match &self.error {
            ErrorType::Io(_) | ErrorType::InputTooLarge => true,
            ErrorType::InternalError(e) if !matches!(e, crate::InternalError::TapeError) => true,
            _ => false,
        }
    }

    /// Indicates if the error that occurred was an early EOF
    #[must_use]
    pub fn is_eof(&self) -> bool {
        matches!(self.error, ErrorType::Eof)
    }

    /// Indicates if the error that occurred was due to a data shape error
    #[must_use]
    pub fn is_data(&self) -> bool {
        // Lazy? maybe but if it aint something else...
        !(self.is_syntax() || self.is_eof() || self.is_io())
    }

    /// Indicates if the error that occurred was due a JSON syntax error
    #[must_use]
    pub fn is_syntax(&self) -> bool {
        // Lazy? maybe but if it aint something else...
        matches!(
            self.error,
            ErrorType::InternalError(crate::InternalError::TapeError) | //This seems to get thrown on some syntax errors
            ErrorType::BadKeyType |
            ErrorType::ExpectedArrayComma |
            ErrorType::ExpectedObjectColon |
            ErrorType::ExpectedMapComma |
            ErrorType::ExpectedMapEnd |
            ErrorType::InvalidEscape |
            ErrorType::InvalidExponent |
            ErrorType::InvalidNumber |
            ErrorType::InvalidUtf8 |
            ErrorType::InvalidUnicodeEscape |
            ErrorType::InvalidUnicodeCodepoint |
            ErrorType::KeyMustBeAString |
            ErrorType::NoStructure |
            ErrorType::Parser |
            ErrorType::Syntax |
            ErrorType::TrailingData |
            ErrorType::UnexpectedCharacter |
            ErrorType::UnterminatedString |
            ErrorType::ExpectedArrayContent |
            ErrorType::ExpectedObjectContent |
            ErrorType::ExpectedObjectKey |
            ErrorType::Overflow |
            ErrorType::SimdUnsupported
        )
    }
}
impl std::error::Error for Error {}

#[cfg(not(tarpaulin_include))]
impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(c) = self.character {
            write!(f, "{:?} at character {} ('{c}')", self.error, self.index)
        } else {
            write!(f, "{:?} at character {}", self.error, self.index)
        }
    }
}

#[cfg(not(tarpaulin_include))]
impl From<Error> for std::io::Error {
    fn from(e: Error) -> Self {
        std::io::Error::new(std::io::ErrorKind::InvalidData, e)
    }
}