1 /++
2 Mir Ion error codes, messages, and exceptions.
3 +/
4 module mir.ion.exception;
5
6 import mir.array.allocation: array;
7 import mir.ndslice.topology: map;
8 import mir.serde: SerdeException;
9 import std.traits: EnumMembers, Unqual;
10
11 /++
12 Ion Error Codes
13 +/
14 enum IonErrorCode
15 {
16 ///
17 none,
18 ///
19 nop,
20 ///
21 jsonUnexpectedValue,
22 ///
23 jsonUnexpectedEnd,
24 ///
25 symbolTableCantInsertKey,
26 ///
27 illegalTypeDescriptor,
28 ///
29 unexpectedEndOfData,
30 ///
31 unexpectedIonType,
32 ///
33 overflowInParseVarUInt,
34 ///
35 overflowInParseVarInt,
36 ///
37 overflowInIntegerValue,
38 ///
39 overflowInDecimalValue,
40 ///
41 overflowInSymbolId,
42 ///
43 zeroAnnotations,
44 ///
45 illegalBinaryData,
46 ///
47 illegalTimeStamp,
48 ///
49 wrongBoolDescriptor,
50 ///
51 wrongIntDescriptor,
52 ///
53 wrongFloatDescriptor,
54 ///
55 nullBool,
56 ///
57 nullInt,
58 ///
59 nullFloat,
60 ///
61 nullTimestamp,
62 ///
63 expectedNullValue,
64 ///
65 expectedBoolValue,
66 ///
67 expectedIntegerValue,
68 ///
69 expectedFloatingValue,
70 ///
71 expectedEnumValue,
72 ///
73 expectedStringValue,
74 ///
75 expectedCharValue,
76 ///
77 expectedStructValue,
78 ///
79 expectedListValue,
80 ///
81 expectedTimestampValue,
82 ///
83 requiredDefaultClassConstructor,
84 ///
85 integerOverflow,
86 ///
87 smallStringOverflow,
88 ///
89 smallArrayOverflow,
90 ///
91 unexpectedVersionMarker,
92 ///
93 cantParseValueStream,
94 ///
95 symbolIdIsTooLargeForTheCurrentSymbolTable,
96 ///
97 invalidLocalSymbolTable,
98 ///
99 sharedSymbolTablesAreUnsupported,
100 ///
101 unableToOpenFile,
102 ///
103 eof,
104 ///
105 errorReadingFile,
106 ///
107 errorReadingStream,
108 ///
109 tooManyElementsForStaticArray,
110 ///
111 notEnoughElementsForStaticArray,
112 ///
113 unusedAnnotations,
114 ///
115 missingAnnotation,
116 ///
117 cantConvertAnnotationToEnum,
118 ///
119 nestedAnnotationsNotAllowed,
120 ///
121 expectedIonStructForAnAssociativeArrayDeserialization,
122 ///
123 unexpectedComma,
124 ///
125 emptyIonInput,
126 ///
127 emptyOrderedStruct,
128 ///
129 negativeIntegerZero,
130 }
131
132 ///
133 version(mir_ion_test) unittest
134 {
135 static assert(!IonErrorCode.none);
136 static assert(IonErrorCode.none == IonErrorCode.init);
137 static assert(IonErrorCode.nop > 0);
138 }
139
140 /++
141 Params:
142 code = $(LREF IonErrorCode)
143 Returns:
144 corresponding error message
145 +/
146 string ionErrorMsg()(IonErrorCode code) @property
147 @safe pure nothrow @nogc
148 {
149 static immutable string[] msgs = [
150 null,
151 "unexpected NOP Padding",
152 "unexpected JSON value",
153 "unexpected JSON end",
154 "symbol table can't insert key",
155 "illegal type descriptor",
156 "unexpected end of data",
157 "unexpected Ion type",
158 "overflow in parseVarUInt",
159 "overflow in parseVarInt",
160 "overflow in integer value",
161 "overflow in decimal value",
162 "overflow in symbol id",
163 "at least one annotation is required",
164 "illegal binary data",
165 "illegal timestamp",
166 "wrong bool descriptor",
167 "wrong int descriptor",
168 "wrong float descriptor",
169 "null bool",
170 "null int",
171 "null float",
172 "null timestamp",
173 "expected null value",
174 "expected boolean value",
175 "expected integer point value",
176 "expected floating value",
177 "expected enum value",
178 "expected string value",
179 "expected char value",
180 "expected struct value",
181 "expected list value",
182 "expected timestamp value",
183 "required default class constructor",
184 "integer overflow",
185 "small string overflow",
186 "small array overflow",
187 "unexpected version marker",
188 "can't parse value stream",
189 "symbol id is too large for the current symbol table",
190 "invalid local symbol table",
191 "shared symbol tables are unsupported",
192 "unable to open file",
193 "end of file",
194 "error reading file",
195 "error reading stream",
196 "too many elements for static array",
197 "not enough elements for static array",
198 "unused annotations",
199 "missing annotation",
200 "can't convert annotation to enum",
201 "nested annotations aren't allowed",
202 "expected IonStruct for an associative array deserialization",
203 "unexpected comma",
204 "Ion data doesn't contain a value",
205 "empty ordered struct",
206 "negative integer zero",
207 ];
208 return msgs[code - IonErrorCode.min];
209 }
210
211 ///
212 @safe pure nothrow @nogc
213 version(mir_ion_test) unittest
214 {
215 static assert(IonErrorCode.nop.ionErrorMsg == "unexpected NOP Padding", IonErrorCode.nop.ionErrorMsg);
216 static assert(IonErrorCode.none.ionErrorMsg is null);
217 }
218
219 version (D_Exceptions):
220
221 /++
222 Mir Ion Exception Class
223 +/
224 class IonException : SerdeException
225 {
226 ///
227 this(
228 string msg,
229 string file = __FILE__,
230 size_t line = __LINE__,
231 Throwable next = null) pure nothrow @nogc @safe
232 {
233 super(msg, file, line, next);
234 }
235
236 ///
237 this(
238 string msg,
239 Throwable next,
240 string file = __FILE__,
241 size_t line = __LINE__,
242 ) pure nothrow @nogc @safe
243 {
244 this(msg, file, line, next);
245 }
246 }
247
248 /++
249 Mir Ion Exception Class
250 +/
251 class IonMirException : IonException
252 {
253 import mir.exception: MirThrowableImpl, mirExceptionInitilizePayloadImpl;
254 private enum maxMsgLen = 447;
255 ///
256 mixin MirThrowableImpl;
257 }
258
259 /++
260 Mir Ion Parser Exception Class
261
262 The exception is used for JSON parsing.
263 +/
264 class IonParserMirException : IonMirException
265 {
266 ///
267 size_t location;
268
269 ///
270 this(
271 scope const(char)[] msg,
272 size_t location,
273 string file = __FILE__,
274 size_t line = __LINE__,
275 Throwable next = null) pure nothrow @nogc @safe
276 {
277 this.location = location;
278 import mir.format: stringBuf, getData;
279 super(stringBuf() << msg << ". location = " << location << getData, file, line, next);
280 }
281
282 ///
283 this(
284 scope const(char)[] msg,
285 size_t location,
286 Throwable next,
287 string file = __FILE__,
288 size_t line = __LINE__,
289 ) pure nothrow @nogc @safe
290 {
291 this(msg, location, file, line, next);
292 }
293 }
294
295 private static immutable IonException[] exceptionsArray =
296 [EnumMembers!IonErrorCode]
297 .map!(code => code ? new IonException("IonException: " ~ code.ionErrorMsg) : null)
298 .array;
299
300 /++
301 Params:
302 code = $(LREF IonErrorCode)
303 Returns:
304 $(LREF IonException)
305 +/
306 IonException ionException(IonErrorCode code) @property
307 @trusted pure nothrow @nogc
308 {
309 pragma(inline, true);
310 return cast(IonException) exceptionsArray[code - IonErrorCode.min];
311 }
312
313 ///
314 @safe pure nothrow @nogc
315 version(mir_ion_test) unittest
316 {
317 static assert(IonErrorCode.nop.ionException.msg == "IonException: unexpected NOP Padding", IonErrorCode.nop.ionException.msg);
318 static assert(IonErrorCode.none.ionException is null);
319 }
320
321 package(mir) Unqual!T unqualException(T)(return T exception) @trusted pure nothrow @nogc
322 // if (is(T : const Exception))
323 {
324 return cast() exception;
325 }