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 }