1#ifndef SIMDJSON_ERROR_H
2#define SIMDJSON_ERROR_H
3
4#include "simdjson/common_defs.h"
5#include <string>
6
7namespace simdjson {
8
9/**
10 * All possible errors returned by simdjson. These error codes are subject to change
11 * and not all simdjson kernel returns the same error code given the same input: it is not
12 * well defined which error a given input should produce.
13 *
14 * Only SUCCESS evaluates to false as a Boolean. All other error codes will evaluate
15 * to true as a Boolean.
16 */
17enum error_code {
18 SUCCESS = 0, ///< No error
19 CAPACITY, ///< This parser can't support a document that big
20 MEMALLOC, ///< Error allocating memory, most likely out of memory
21 TAPE_ERROR, ///< Something went wrong, this is a generic error
22 DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
23 STRING_ERROR, ///< Problem while parsing a string
24 T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
25 F_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 'f'
26 N_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 'n'
27 NUMBER_ERROR, ///< Problem while parsing a number
28 UTF8_ERROR, ///< the input is not valid UTF-8
29 UNINITIALIZED, ///< unknown error, or uninitialized document
30 EMPTY, ///< no structural element found
31 UNESCAPED_CHARS, ///< found unescaped characters in a string.
32 UNCLOSED_STRING, ///< missing quote at the end
33 UNSUPPORTED_ARCHITECTURE, ///< unsupported architecture
34 INCORRECT_TYPE, ///< JSON element has a different type than user expected
35 NUMBER_OUT_OF_RANGE, ///< JSON number does not fit in 64 bits
36 INDEX_OUT_OF_BOUNDS, ///< JSON array index too large
37 NO_SUCH_FIELD, ///< JSON field not found in object
38 IO_ERROR, ///< Error reading a file
39 INVALID_JSON_POINTER, ///< Invalid JSON pointer reference
40 INVALID_URI_FRAGMENT, ///< Invalid URI fragment
41 UNEXPECTED_ERROR, ///< indicative of a bug in simdjson
42 PARSER_IN_USE, ///< parser is already in use.
43 OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order
44 INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
45 INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
46 SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
47 OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
48 TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
49 NUM_ERROR_CODES
50};
51
52/**
53 * Get the error message for the given error code.
54 *
55 * dom::parser parser;
56 * dom::element doc;
57 * auto error = parser.parse("foo",3).get(doc);
58 * if (error) { printf("Error: %s\n", error_message(error)); }
59 *
60 * @return The error message.
61 */
62inline const char *error_message(error_code error) noexcept;
63
64/**
65 * Write the error message to the output stream
66 */
67inline std::ostream& operator<<(std::ostream& out, error_code error) noexcept;
68
69/**
70 * Exception thrown when an exception-supporting simdjson method is called
71 */
72struct simdjson_error : public std::exception {
73 /**
74 * Create an exception from a simdjson error code.
75 * @param error The error code
76 */
77 simdjson_error(error_code error) noexcept : _error{error} { }
78 /** The error message */
79 const char *what() const noexcept { return error_message(error: error()); }
80 /** The error code */
81 error_code error() const noexcept { return _error; }
82private:
83 /** The error code that was used */
84 error_code _error;
85};
86
87namespace internal {
88
89/**
90 * The result of a simdjson operation that could fail.
91 *
92 * Gives the option of reading error codes, or throwing an exception by casting to the desired result.
93 *
94 * This is a base class for implementations that want to add functions to the result type for
95 * chaining.
96 *
97 * Override like:
98 *
99 * struct simdjson_result<T> : public internal::simdjson_result_base<T> {
100 * simdjson_result() noexcept : internal::simdjson_result_base<T>() {}
101 * simdjson_result(error_code error) noexcept : internal::simdjson_result_base<T>(error) {}
102 * simdjson_result(T &&value) noexcept : internal::simdjson_result_base<T>(std::forward(value)) {}
103 * simdjson_result(T &&value, error_code error) noexcept : internal::simdjson_result_base<T>(value, error) {}
104 * // Your extra methods here
105 * }
106 *
107 * Then any method returning simdjson_result<T> will be chainable with your methods.
108 */
109template<typename T>
110struct simdjson_result_base : protected std::pair<T, error_code> {
111
112 /**
113 * Create a new empty result with error = UNINITIALIZED.
114 */
115 simdjson_inline simdjson_result_base() noexcept;
116
117 /**
118 * Create a new error result.
119 */
120 simdjson_inline simdjson_result_base(error_code error) noexcept;
121
122 /**
123 * Create a new successful result.
124 */
125 simdjson_inline simdjson_result_base(T &&value) noexcept;
126
127 /**
128 * Create a new result with both things (use if you don't want to branch when creating the result).
129 */
130 simdjson_inline simdjson_result_base(T &&value, error_code error) noexcept;
131
132 /**
133 * Move the value and the error to the provided variables.
134 *
135 * @param value The variable to assign the value to. May not be set if there is an error.
136 * @param error The variable to assign the error to. Set to SUCCESS if there is no error.
137 */
138 simdjson_inline void tie(T &value, error_code &error) && noexcept;
139
140 /**
141 * Move the value to the provided variable.
142 *
143 * @param value The variable to assign the value to. May not be set if there is an error.
144 */
145 simdjson_inline error_code get(T &value) && noexcept;
146
147 /**
148 * The error.
149 */
150 simdjson_inline error_code error() const noexcept;
151
152#if SIMDJSON_EXCEPTIONS
153
154 /**
155 * Get the result value.
156 *
157 * @throw simdjson_error if there was an error.
158 */
159 simdjson_inline T& value() & noexcept(false);
160
161 /**
162 * Take the result value (move it).
163 *
164 * @throw simdjson_error if there was an error.
165 */
166 simdjson_inline T&& value() && noexcept(false);
167
168 /**
169 * Take the result value (move it).
170 *
171 * @throw simdjson_error if there was an error.
172 */
173 simdjson_inline T&& take_value() && noexcept(false);
174
175 /**
176 * Cast to the value (will throw on error).
177 *
178 * @throw simdjson_error if there was an error.
179 */
180 simdjson_inline operator T&&() && noexcept(false);
181#endif // SIMDJSON_EXCEPTIONS
182
183 /**
184 * Get the result value. This function is safe if and only
185 * the error() method returns a value that evaluates to false.
186 */
187 simdjson_inline const T& value_unsafe() const& noexcept;
188
189 /**
190 * Take the result value (move it). This function is safe if and only
191 * the error() method returns a value that evaluates to false.
192 */
193 simdjson_inline T&& value_unsafe() && noexcept;
194
195}; // struct simdjson_result_base
196
197} // namespace internal
198
199/**
200 * The result of a simdjson operation that could fail.
201 *
202 * Gives the option of reading error codes, or throwing an exception by casting to the desired result.
203 */
204template<typename T>
205struct simdjson_result : public internal::simdjson_result_base<T> {
206 /**
207 * @private Create a new empty result with error = UNINITIALIZED.
208 */
209 simdjson_inline simdjson_result() noexcept;
210 /**
211 * @private Create a new error result.
212 */
213 simdjson_inline simdjson_result(T &&value) noexcept;
214 /**
215 * @private Create a new successful result.
216 */
217 simdjson_inline simdjson_result(error_code error_code) noexcept;
218 /**
219 * @private Create a new result with both things (use if you don't want to branch when creating the result).
220 */
221 simdjson_inline simdjson_result(T &&value, error_code error) noexcept;
222
223 /**
224 * Move the value and the error to the provided variables.
225 *
226 * @param value The variable to assign the value to. May not be set if there is an error.
227 * @param error The variable to assign the error to. Set to SUCCESS if there is no error.
228 */
229 simdjson_inline void tie(T &value, error_code &error) && noexcept;
230
231 /**
232 * Move the value to the provided variable.
233 *
234 * @param value The variable to assign the value to. May not be set if there is an error.
235 */
236 simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept;
237
238 /**
239 * The error.
240 */
241 simdjson_inline error_code error() const noexcept;
242
243#if SIMDJSON_EXCEPTIONS
244
245 /**
246 * Get the result value.
247 *
248 * @throw simdjson_error if there was an error.
249 */
250 simdjson_inline T& value() & noexcept(false);
251
252 /**
253 * Take the result value (move it).
254 *
255 * @throw simdjson_error if there was an error.
256 */
257 simdjson_inline T&& value() && noexcept(false);
258
259 /**
260 * Take the result value (move it).
261 *
262 * @throw simdjson_error if there was an error.
263 */
264 simdjson_inline T&& take_value() && noexcept(false);
265
266 /**
267 * Cast to the value (will throw on error).
268 *
269 * @throw simdjson_error if there was an error.
270 */
271 simdjson_inline operator T&&() && noexcept(false);
272#endif // SIMDJSON_EXCEPTIONS
273
274 /**
275 * Get the result value. This function is safe if and only
276 * the error() method returns a value that evaluates to false.
277 */
278 simdjson_inline const T& value_unsafe() const& noexcept;
279
280 /**
281 * Take the result value (move it). This function is safe if and only
282 * the error() method returns a value that evaluates to false.
283 */
284 simdjson_inline T&& value_unsafe() && noexcept;
285
286}; // struct simdjson_result
287
288#if SIMDJSON_EXCEPTIONS
289
290template<typename T>
291inline std::ostream& operator<<(std::ostream& out, simdjson_result<T> value) { return out << value.value(); }
292#endif // SIMDJSON_EXCEPTIONS
293
294#ifndef SIMDJSON_DISABLE_DEPRECATED_API
295/**
296 * @deprecated This is an alias and will be removed, use error_code instead
297 */
298using ErrorValues [[deprecated("This is an alias and will be removed, use error_code instead")]] = error_code;
299
300/**
301 * @deprecated Error codes should be stored and returned as `error_code`, use `error_message()` instead.
302 */
303[[deprecated("Error codes should be stored and returned as `error_code`, use `error_message()` instead.")]]
304inline const std::string error_message(int error) noexcept;
305#endif // SIMDJSON_DISABLE_DEPRECATED_API
306} // namespace simdjson
307
308#endif // SIMDJSON_ERROR_H
309