1 /++ 2 +/ 3 module mir.ion.stream; 4 5 import mir.ion.exception; 6 import mir.ion.type_code; 7 import mir.ion.value; 8 import mir.utility: _expect; 9 10 /++ 11 Ion Value Stream 12 13 Note: this implementation of value stream doesn't support shared symbol tables. 14 +/ 15 struct IonValueStream 16 { 17 /// data view. 18 const(ubyte)[] data; 19 20 private alias DG = int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) @safe pure nothrow @nogc; 21 private alias EDG = int delegate(scope const(char[])[] symbolTable, scope IonDescribedValue value) @safe pure @nogc; 22 23 const: 24 25 // 26 void toString(W)(scope ref W w) scope 27 { 28 import mir.ser.json: serializeJson; 29 return serializeJson(w, this); 30 } 31 32 version (D_Exceptions) 33 { 34 /++ 35 +/ 36 @safe pure @nogc 37 scope int opApply(scope int delegate(scope const(char[])[] symbolTable, scope IonDescribedValue value) @safe pure @nogc dg) 38 { 39 return opApply((IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) { 40 if (_expect(error, false)) 41 throw error.ionException; 42 return dg(symbolTable, value); 43 }); 44 } 45 46 /// ditto 47 @trusted @nogc 48 scope int opApply(scope int delegate(scope const(char[])[] symbolTable, scope IonDescribedValue value) 49 @safe @nogc dg) { return opApply(cast(EDG) dg); } 50 51 /// ditto 52 @trusted pure 53 scope int opApply(scope int delegate(scope const(char[])[] symbolTable, scope IonDescribedValue value) 54 @safe pure dg) { return opApply(cast(EDG) dg); } 55 56 /// ditto 57 @trusted 58 scope int opApply(scope int delegate(scope const(char[])[] symbolTable, scope IonDescribedValue value) 59 @safe dg) { return opApply(cast(EDG) dg); } 60 61 /// ditto 62 @system pure @nogc 63 scope int opApply(scope int delegate(scope const(char[])[] symbolTable, scope IonDescribedValue value) 64 @system pure @nogc dg) { return opApply(cast(EDG) dg); } 65 66 /// ditto 67 @system @nogc 68 scope int opApply(scope int delegate(scope const(char[])[] symbolTable, scope IonDescribedValue value) 69 @system @nogc dg) { return opApply(cast(EDG) dg); } 70 71 /// ditto 72 @system pure 73 scope int opApply(scope int delegate(scope const(char[])[] symbolTable, scope IonDescribedValue value) 74 @system pure dg) { return opApply(cast(EDG) dg); } 75 76 /// ditto 77 @system 78 scope int opApply(scope int delegate(scope const(char[])[] symbolTable, scope IonDescribedValue value) 79 @system dg) { return opApply(cast(EDG) dg); } 80 } 81 82 /++ 83 +/ 84 @trusted pure nothrow @nogc 85 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) @safe pure nothrow @nogc dg) 86 { 87 import mir.appender: ScopedBuffer; 88 import mir.ion.symbol_table; 89 90 ScopedBuffer!(const(char)[]) symbolTableBuffer = void; 91 symbolTableBuffer.initialize; 92 93 const(ubyte)[] d = data; 94 95 void resetSymbolTable() 96 { 97 symbolTableBuffer.reset; 98 symbolTableBuffer.put(IonSystemSymbolTable_v1); 99 } 100 101 while (d.length) 102 { 103 IonErrorCode error; 104 IonVersionMarker versionMarker; 105 IonDescribedValue describedValue; 106 error = d.parseVersion(versionMarker); 107 if (!error) 108 { 109 if (versionMarker != IonVersionMarker(1, 0)) 110 { 111 error = IonErrorCode.unexpectedVersionMarker; 112 goto C; 113 } 114 resetSymbolTable(); 115 continue; 116 } 117 describedValue = d.parseValue(error); 118 if (error == IonErrorCode.nop) 119 continue; 120 // check if describedValue is symbol table 121 if (describedValue.descriptor.type == IonTypeCode.annotations) 122 { 123 auto annotationWrapper = describedValue.get!IonAnnotationWrapper(error); 124 IonAnnotations annotations = annotationWrapper.annotations; 125 IonDescribedValue symbolTableValue = annotationWrapper.value; 126 if (!error && !annotations.empty) 127 { 128 // check first annotation is $ion_symbol_table 129 { 130 bool nextAnnotation; 131 foreach (IonErrorCode annotationError, size_t annotationId; annotations) 132 { 133 error = annotationError; 134 if (error) 135 goto C; 136 if (nextAnnotation) 137 continue; 138 nextAnnotation = true; 139 if (annotationId != IonSystemSymbol.ion_symbol_table) 140 goto C; 141 } 142 } 143 IonStruct symbolTableStruct; 144 if (symbolTableValue.descriptor.type != IonTypeCode.struct_) 145 { 146 error = IonErrorCode.expectedStructValue; 147 goto C; 148 } 149 if (symbolTableValue != null) 150 { 151 symbolTableStruct = symbolTableValue.trustedGet!IonStruct; 152 } 153 154 { 155 bool preserveCurrentSymbols; 156 IonList symbols; 157 158 foreach (IonErrorCode symbolTableError, size_t symbolTableKeyId, scope IonDescribedValue elementValue; symbolTableStruct) 159 { 160 error = symbolTableError; 161 if (error) 162 goto C; 163 switch (symbolTableKeyId) 164 { 165 case IonSystemSymbol.imports: 166 { 167 if (preserveCurrentSymbols || (elementValue.descriptor.type != IonTypeCode.symbol && elementValue.descriptor.type != IonTypeCode.list)) 168 { 169 error = IonErrorCode.invalidLocalSymbolTable; 170 goto C; 171 } 172 if (elementValue.descriptor.type == IonTypeCode.list) 173 { 174 error = IonErrorCode.sharedSymbolTablesAreUnsupported; 175 goto C; 176 } 177 size_t id; 178 error = elementValue.trustedGet!IonSymbolID.get(id); 179 if (error) 180 goto C; 181 if (id != IonSystemSymbol.ion_symbol_table) 182 { 183 error = IonErrorCode.invalidLocalSymbolTable; 184 goto C; 185 } 186 preserveCurrentSymbols = true; 187 break; 188 } 189 case IonSystemSymbol.symbols: 190 { 191 if (symbols != symbols.init || elementValue.descriptor.type != IonTypeCode.list) 192 { 193 error = IonErrorCode.invalidLocalSymbolTable; 194 goto C; 195 } 196 if (elementValue != null) 197 { 198 symbols = elementValue.trustedGet!IonList; 199 } 200 if (error) 201 goto C; 202 break; 203 } 204 default: 205 { 206 //CHECK: should other symbols be ignored? 207 continue; 208 } 209 } 210 } 211 212 if (!preserveCurrentSymbols) 213 { 214 resetSymbolTable(); 215 } 216 217 foreach (IonErrorCode symbolsError, scope IonDescribedValue symbolValue; symbols) 218 { 219 error = symbolsError; 220 if (error) 221 goto C; 222 auto symbol = symbolValue.get!(const(char)[])(error); 223 if (error) 224 goto C; 225 symbolTableBuffer.put(symbol); 226 } 227 continue; 228 } 229 } 230 // TODO: continue work 231 } 232 C: 233 if (auto ret = dg(error, symbolTableBuffer.data, describedValue)) 234 return ret; 235 } 236 return 0; 237 } 238 239 /// ditto 240 @trusted nothrow @nogc 241 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 242 @safe nothrow @nogc dg) { return opApply(cast(DG) dg); } 243 244 /// ditto 245 @trusted pure @nogc 246 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 247 @safe pure @nogc dg) { return opApply(cast(DG) dg); } 248 249 /// ditto 250 @trusted pure nothrow 251 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 252 @safe pure nothrow dg) { return opApply(cast(DG) dg); } 253 254 /// ditto 255 @trusted @nogc 256 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 257 @safe @nogc dg) { return opApply(cast(DG) dg); } 258 259 /// ditto 260 @trusted pure 261 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 262 @safe pure dg) { return opApply(cast(DG) dg); } 263 264 /// ditto 265 @trusted nothrow 266 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 267 @safe nothrow dg) { return opApply(cast(DG) dg); } 268 269 /// ditto 270 @trusted 271 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 272 @safe dg) { return opApply(cast(DG) dg); } 273 274 /// ditto 275 @system pure nothrow @nogc 276 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 277 @system pure nothrow @nogc dg) { return opApply(cast(DG) dg); } 278 279 /// ditto 280 @system nothrow @nogc 281 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 282 @system nothrow @nogc dg) { return opApply(cast(DG) dg); } 283 284 /// ditto 285 @system pure @nogc 286 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 287 @system pure @nogc dg) { return opApply(cast(DG) dg); } 288 289 /// ditto 290 @system pure nothrow 291 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 292 @system pure nothrow dg) { return opApply(cast(DG) dg); } 293 294 /// ditto 295 @system @nogc 296 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 297 @system @nogc dg) { return opApply(cast(DG) dg); } 298 299 /// ditto 300 @system pure 301 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 302 @system pure dg) { return opApply(cast(DG) dg); } 303 304 /// ditto 305 @system nothrow 306 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 307 @system nothrow dg) { return opApply(cast(DG) dg); } 308 309 /// ditto 310 @system 311 scope int opApply(scope int delegate(IonErrorCode error, scope const(char[])[] symbolTable, scope IonDescribedValue value) 312 @system dg) { return opApply(cast(DG) dg); } 313 314 /++ 315 Params: 316 serializer = serializer 317 +/ 318 void serialize(S)(scope ref S serializer) scope const @safe 319 { 320 bool following; 321 foreach (scope symbolTable, scope value; this) 322 { 323 if (following) 324 serializer.nextTopLevelValue; 325 following = true; 326 // static if (__traits(hasMember, serializer, "putKeyId")) 327 // { 328 // alias unwrappedSerializer = serializer; 329 // } 330 // else 331 // { 332 import mir.ser.unwrap_ids; 333 auto unwrappedSerializer = unwrapSymbolIds((()@trusted => &serializer)(), symbolTable); 334 // } 335 value.serialize(unwrappedSerializer); 336 } 337 } 338 339 /// 340 @safe pure 341 unittest 342 { 343 import mir.ser.json; 344 const ubyte[] data = [0xe0, 0x01, 0x00, 0xea, 0xe9, 0x81, 0x83, 0xd6, 0x87, 0xb4, 0x81, 0x61, 0x81, 0x62, 0xd6, 0x8a, 0x21, 0x01, 0x8b, 0x21, 0x02]; 345 auto json = data.IonValueStream.serializeJson; 346 assert(json == `{"a":1,"b":2}`); 347 } 348 }