1 module google.protobuf.struct_; 2 3 import std.json : JSONValue; 4 import google.protobuf; 5 6 class Struct 7 { 8 @Proto(1) Value[string] fields = protoDefaultValue!(Value[string]); 9 10 this() 11 { 12 } 13 14 this(JSONValue value) 15 { 16 fromJSONValue(value); 17 } 18 19 JSONValue toJSONValue()() 20 { 21 import std.array : assocArray; 22 import std.algorithm : map; 23 import std.typecons : tuple; 24 25 return JSONValue(fields.byKeyValue.map!(a => tuple(a.key, a.value.toJSONValue)).assocArray); 26 } 27 28 auto fromJSONValue()(JSONValue value) 29 { 30 import std.array : assocArray; 31 import std.algorithm : map; 32 import std.exception : enforce; 33 import std.json : JSONType; 34 import std.typecons : tuple; 35 36 if (value.type == JSONType.null_) 37 { 38 fields = protoDefaultValue!(Value[string]); 39 return this; 40 } 41 42 enforce!ProtobufException(value.type == JSONType.object, "JSON object expected"); 43 fields = value.object.byKeyValue.map!(a => tuple(a.key, new Value(a.value))).assocArray; 44 45 return this; 46 } 47 } 48 49 class Value 50 { 51 enum KindCase 52 { 53 kindNotSet = 0, 54 nullValue = 1, 55 numberValue = 2, 56 stringValue = 3, 57 boolValue = 4, 58 structValue = 5, 59 listValue = 6, 60 } 61 KindCase _kindCase = KindCase.kindNotSet; 62 @property KindCase kindCase() { return _kindCase; } 63 void clearKind() { _kindCase = KindCase.kindNotSet; } 64 @Oneof("_kindCase") union 65 { 66 @Proto(1) NullValue _nullValue = protoDefaultValue!NullValue; mixin(oneofAccessors!_nullValue); 67 @Proto(2) double _numberValue; mixin(oneofAccessors!_numberValue); 68 @Proto(3) string _stringValue; mixin(oneofAccessors!_stringValue); 69 @Proto(4) bool _boolValue; mixin(oneofAccessors!_boolValue); 70 @Proto(5) Struct _structValue; mixin(oneofAccessors!_structValue); 71 @Proto(6) ListValue _listValue; mixin(oneofAccessors!_listValue); 72 } 73 74 this() 75 { 76 } 77 78 this(JSONValue jsonValue) 79 { 80 fromJSONValue(jsonValue); 81 } 82 83 override bool opEquals(Object o) 84 { 85 auto other = cast(Value) o; 86 if (other is null) 87 return false; 88 89 if (kindCase != other.kindCase) 90 return false; 91 92 final switch (kindCase) 93 { 94 case KindCase.kindNotSet: 95 return true; 96 case KindCase.nullValue: 97 return nullValue == other.nullValue; 98 case KindCase.numberValue: 99 return numberValue == other.numberValue; 100 case KindCase.stringValue: 101 return stringValue == other.stringValue; 102 case KindCase.boolValue: 103 return boolValue == other.boolValue; 104 case KindCase.structValue: 105 return structValue == other.structValue; 106 case KindCase.listValue: 107 return listValue == other.listValue; 108 } 109 } 110 111 JSONValue toJSONValue()() 112 { 113 import std.array : array, assocArray; 114 import std.algorithm : map; 115 import std.typecons : tuple; 116 117 final switch (kindCase) 118 { 119 case KindCase.kindNotSet: 120 return JSONValue(null); 121 case KindCase.nullValue: 122 return JSONValue(null); 123 case KindCase.numberValue: 124 return JSONValue(numberValue); 125 case KindCase.stringValue: 126 return JSONValue(stringValue); 127 case KindCase.boolValue: 128 return JSONValue(boolValue); 129 case KindCase.structValue: 130 return JSONValue(structValue.fields.byKeyValue.map!(a => tuple(a.key, a.value.toJSONValue)).assocArray); 131 case KindCase.listValue: 132 return JSONValue(listValue.values.map!(a => a.toJSONValue).array); 133 } 134 } 135 136 auto fromJSONValue()(JSONValue jsonValue) 137 { 138 import std.array : array, assocArray; 139 import std.algorithm : map; 140 import std.json : JSONType; 141 import std.typecons : tuple; 142 143 switch (jsonValue.type) 144 { 145 case JSONType.null_: 146 nullValue = NullValue.NULL_VALUE; 147 break; 148 case JSONType..string: 149 stringValue = jsonValue.str; 150 break; 151 case JSONType.integer: 152 numberValue = jsonValue.integer; 153 break; 154 case JSONType.uinteger: 155 numberValue = jsonValue.uinteger; 156 break; 157 case JSONType.float_: 158 numberValue = jsonValue.floating; 159 break; 160 case JSONType.object: 161 if (structValue is null) 162 structValue = new Struct; 163 structValue.fields = jsonValue.object.byKeyValue.map!(a => tuple(a.key, new Value(a.value))).assocArray; 164 break; 165 case JSONType.array: 166 if (listValue is null) 167 listValue = new ListValue; 168 listValue.values = jsonValue.array.map!(a => new Value(a)).array; 169 break; 170 case JSONType.true_: 171 boolValue = true; 172 break; 173 case JSONType.false_: 174 boolValue = false; 175 break; 176 default: 177 throw new ProtobufException("Unexpected JSON type"); 178 } 179 180 return this; 181 } 182 } 183 184 enum NullValue 185 { 186 NULL_VALUE = 0, 187 } 188 189 class ListValue 190 { 191 @Proto(1) Value[] values = protoDefaultValue!(Value[]); 192 193 this() 194 { 195 } 196 197 this(JSONValue value) 198 { 199 fromJSONValue(value); 200 } 201 202 JSONValue toJSONValue()() 203 { 204 import std.array : array; 205 import std.algorithm : map; 206 207 return JSONValue(values.map!(a => a.toJSONValue).array); 208 } 209 210 auto fromJSONValue()(JSONValue value) 211 { 212 import std.array : array; 213 import std.algorithm : map; 214 import std.exception : enforce; 215 import std.json : JSONType; 216 217 if (value.type == JSONType.null_) 218 { 219 values = protoDefaultValue!(Value[]); 220 return this; 221 } 222 223 enforce!ProtobufException(value.type == JSONType.array, "JSON array expected"); 224 values = value.array.map!(a => new Value(a)).array; 225 226 return this; 227 } 228 }