1 /++ 2 $(H4 High level Ion deserialization API) 3 4 Macros: 5 IONREF = $(REF_ALTTEXT $(TT $2), $2, mir, ion, $1)$(NBSP) 6 +/ 7 module mir.deser.ion; 8 9 private alias AliasSeq(T...) = T; 10 11 /++ 12 +/ 13 template deserializeIon(T, bool annotated = false) 14 { 15 import mir.ion.value: IonDescribedValue, IonAnnotations; 16 17 static if (annotated) 18 alias OptIonAnnotations = IonAnnotations; 19 else 20 alias OptIonAnnotations = AliasSeq!(); 21 22 /++ 23 +/ 24 T deserializeIon()(scope const char[][] symbolTable, scope IonDescribedValue ionValue, scope OptIonAnnotations optionalAnnotations) 25 { 26 T value; 27 deserializeIon(value, symbolTable, ionValue, optionalAnnotations); 28 return value; 29 } 30 31 /// ditto 32 void deserializeIon()( 33 scope ref T value, scope const char[][] symbolTable, 34 scope IonDescribedValue ionValue, 35 scope OptIonAnnotations optionalAnnotations) 36 { 37 import std.meta: anySatisfy; 38 import mir.algebraic: Algebraic; 39 import std.traits: isDynamicArray; 40 static if (is(immutable T : immutable Algebraic!TypeSet, TypeSet...) 41 && anySatisfy!(isDynamicArray, Algebraic!TypeSet.AllowedTypes)) 42 { 43 import mir.ndslice.topology: map; 44 import mir.array.allocation: array; 45 deserializeIon(value, symbolTable.map!idup.array, ionValue, optionalAnnotations); 46 } 47 else 48 { 49 import mir.appender: scopedBuffer; 50 import mir.deser: hasDeserializeFromIon, deserializeValue, TableKind; 51 import mir.serde: serdeGetDeserializationKeysRecurse; 52 import mir.string_table: createTable; 53 54 static if (hasDeserializeFromIon!T) 55 enum keys = string[].init; 56 else 57 enum keys = serdeGetDeserializationKeysRecurse!T; 58 59 alias createTableChar = createTable!char; 60 static immutable table = createTableChar!(keys, false); 61 62 auto tableMapBuffer = scopedBuffer!(uint, 1024); 63 foreach (key; symbolTable) 64 { 65 uint id; 66 if (!table.get(key, id)) 67 id = uint.max; 68 tableMapBuffer.put(id); 69 } 70 if (auto exception = deserializeValue!(keys, TableKind.scopeRuntime)(ionValue, value, symbolTable, tableMapBuffer.data, optionalAnnotations)) 71 throw (() @trusted => cast() exception)(); 72 }} 73 74 /// ditto 75 // the same code with GC allocated symbol table 76 T deserializeIon(const string[] symbolTable, scope IonDescribedValue ionValue, scope OptIonAnnotations optionalAnnotations) 77 { 78 T value; 79 deserializeIon(value, symbolTable, ionValue, optionalAnnotations); 80 return value; 81 } 82 83 /// ditto 84 void deserializeIon()(scope ref T value, const string[] symbolTable, scope IonDescribedValue ionValue, scope OptIonAnnotations optionalAnnotations) 85 { 86 import mir.appender: scopedBuffer; 87 import mir.deser: hasDeserializeFromIon, deserializeValue, TableKind; 88 import mir.serde: serdeGetDeserializationKeysRecurse; 89 import mir.string_table: MirStringTable; 90 91 static if (hasDeserializeFromIon!T) 92 static immutable keys = string[].init; 93 else 94 static immutable keys = serdeGetDeserializationKeysRecurse!T; 95 96 alias Table = MirStringTable!(keys.length, keys.length ? keys[$ - 1].length : 0); 97 98 static if (keys.length) 99 static immutable table = Table(keys[0 .. keys.length]); 100 else 101 static immutable table = Table.init; 102 103 auto tableMapBuffer = scopedBuffer!(uint, 1024); 104 105 foreach (key; symbolTable) 106 { 107 uint id; 108 if (!table.get(key, id)) 109 id = uint.max; 110 tableMapBuffer.put(id); 111 } 112 113 if (auto exception = deserializeValue!(keys, TableKind.immutableRuntime)(ionValue, value, symbolTable, tableMapBuffer.data, optionalAnnotations)) 114 throw exception; 115 } 116 117 static if (!annotated) 118 { 119 /++ 120 +/ 121 T deserializeIon()(scope const(ubyte)[] data) 122 { 123 T value; 124 deserializeIon(value, data); 125 return value; 126 } 127 128 /// ditto 129 void deserializeIon()(scope ref T value, scope const(ubyte)[] data) 130 { 131 import mir.ion.stream: IonValueStream; 132 import mir.ion.exception: IonErrorCode, ionException; 133 134 foreach (symbolTable, scope ionValue; data.IonValueStream) 135 { 136 return .deserializeIon!T(value, symbolTable, ionValue); 137 } 138 139 throw IonErrorCode.emptyIonInput.ionException; 140 } 141 } 142 } 143 144 version(mir_ion_test) 145 unittest 146 { 147 alias d = deserializeIon!(int[string]); 148 import mir.ion.value; 149 enum EEE { a, b } 150 alias deserNull = deserializeIon!EEE; 151 }