1 module hunt.serialization.specify; 2 3 import std.traits; 4 import std.range; 5 import hunt.serialization.BinarySerializer; 6 import hunt.serialization.BinaryDeserializer; 7 8 template PtrType(T) { 9 static if(is(T == bool) || is(T == char)) { 10 alias PtrType = ubyte*; 11 } else static if(is(T == float)) { 12 alias PtrType = uint*; 13 } else static if(is(T == double)) { 14 alias PtrType = ulong*; 15 } else { 16 alias PtrType = Unsigned!T*; 17 } 18 } 19 20 enum NULL = [110, 117, 108, 108]; 21 22 void specify(C, T)(auto ref C obj, ref T val) if(is(T == wchar)) { 23 specify(obj , *cast(ushort*)&val); 24 } 25 26 void specify(C, T)(auto ref C obj, ref T val) if(is(T == dchar)) { 27 specify(obj , *cast(uint*)&val); 28 } 29 30 void specify(C, T)(auto ref C obj, ref T val) if(is(T == ushort)) { 31 ubyte valh = (val >> 8); 32 ubyte vall = val & 0xff; 33 obj.putUbyte(valh); 34 obj.putUbyte(vall); 35 val = (valh << 8) + vall; 36 } 37 38 void specify(C, T)(auto ref C obj, ref T val) if(is(T == uint)) { 39 ubyte val0 = (val >> 24); 40 ubyte val1 = cast(ubyte)(val >> 16); 41 ubyte val2 = cast(ubyte)(val >> 8); 42 ubyte val3 = val & 0xff; 43 obj.putUbyte(val0); 44 obj.putUbyte(val1); 45 obj.putUbyte(val2); 46 obj.putUbyte(val3); 47 val = (val0 << 24) + (val1 << 16) + (val2 << 8) + val3; 48 } 49 50 void specify(C, T)(auto ref C obj, ref T val) if(is(T == ulong)) { 51 T newVal; 52 for(int i = 0; i < T.sizeof; ++i) { 53 immutable shiftBy = 64 - (i + 1) * T.sizeof; 54 ubyte byteVal = (val >> shiftBy) & 0xff; 55 obj.putUbyte(byteVal); 56 newVal |= (cast(T)byteVal << shiftBy); 57 } 58 val = newVal; 59 } 60 61 //静态数组 62 void specify(C, T)(auto ref C obj, ref T val) if(isStaticArray!T) { 63 static if(is(Unqual!(ElementType!T): ubyte) && T.sizeof == 1) 64 { 65 obj.putRaw(cast(ubyte[])val); 66 } 67 else 68 { 69 foreach(ref v; val) 70 { 71 specify(obj ,v); 72 } 73 } 74 } 75 76 //string 77 void specify(C, T)(auto ref C obj, ref T val) if(is(T == string)) 78 { 79 ushort len = cast(ushort)val.length; 80 specify(obj , len); 81 82 static if (is (C == BinarySerializer)) 83 { 84 obj.putRaw(cast(ubyte[])val); 85 } 86 else 87 { 88 val = cast(string) obj.putRaw(len).idup; 89 } 90 } 91 92 //基础类型数组 93 void specify(C, T)(auto ref C obj, ref T val) if(isAssociativeArray!T) 94 { 95 ushort length = cast(ushort)val.length; 96 specify(obj , length); 97 const keys = val.keys; 98 for(ushort i = 0; i < length; ++i) { 99 KeyType!T k = keys.length ? keys[i] : KeyType!T.init; 100 auto v = keys.length ? val[k] : ValueType!T.init; 101 102 specify(obj ,k); 103 specify(obj ,v); 104 val[k] = v; 105 } 106 } 107 108 void specify(C, T)(auto ref C obj, ref T val) if(isPointer!T) { 109 alias ValueType = PointerTarget!T; 110 specify(obj , *val); 111 } 112 113 114 115 //ubyte 116 void specify(C, T)(auto ref C obj, ref T val) if(is(T == ubyte)) 117 { 118 obj.putUbyte(val); 119 } 120 121 //有符号类型 122 void specify(C, T)(auto ref C obj, ref T val) if(!is(T == enum) && (isSigned!T || isBoolean!T || is(T == char) || isFloatingPoint!T)) 123 { 124 specifyPtr(obj , val); 125 } 126 127 //ENUM 128 void specify(C, T)(auto ref C obj, ref T val) if(is(T == enum)) 129 { 130 specify(obj , cast(Unqual!(OriginalType!(T)))val ); 131 } 132 133 void specify(C, T)(auto ref C obj, ref T val) if(is(C == BinarySerializer) && isInputRange!T && !isInfinite!T && !is(T == string) && !isStaticArray!T && !isAssociativeArray!T) 134 { 135 enum hasLength = is(typeof(() { auto l = val.length; })); 136 ushort length = cast(ushort)val.length; 137 specify(obj, length); 138 139 static if(hasSlicing!(Unqual!T) && is(Unqual!(ElementType!T): ubyte) && T.sizeof == 1) 140 { 141 obj.putRaw(cast(ubyte[])val.array); 142 } 143 else 144 { 145 foreach(ref v; val) 146 { 147 specify(obj , v); 148 } 149 } 150 } 151 152 153 void specify(C, T)(auto ref C obj, ref T val) if(isAggregateType!T && !isInputRange!T && !isOutputRange!(T, ubyte)) 154 { 155 loopMembers(obj , val); 156 } 157 158 //自定义数组 159 void specify(C, T)(auto ref C obj, ref T val) if(isDecerealiser!C && !isOutputRange!(T, ubyte) && isDynamicArray!T && !is(T == string)) { 160 ushort length; 161 162 specify(obj,length); 163 decerealiseArrayImpl(obj, val, length); 164 } 165 166 void decerealiseArrayImpl(C, T, U)(auto ref C obj, ref T val, U length) if(is(T == E[], E) && isDecerealiser!C) 167 { 168 169 ulong neededBytes(T)(ulong length) { 170 alias E = ElementType!T; 171 static if(isScalarType!E) 172 return length * E.sizeof; 173 else static if(isInputRange!E) 174 return neededBytes!E(length); 175 else 176 return 0; 177 } 178 179 immutable needed = neededBytes!T(length); 180 181 static if(is(Unqual!(ElementType!T): ubyte) && T.sizeof == 1) { 182 val = obj.putRaw(length).dup; 183 } else { 184 if(val.length != length) val.length = cast(uint)length; 185 foreach(ref e; val) obj.specify(e); 186 } 187 } 188 189 190 void specifyPtr(C, T)(auto ref C obj, ref T val) 191 { 192 auto ptr = cast(PtrType!T)(&val); 193 specify(obj , *ptr); 194 } 195 196 void loopMembers(C, T)(auto ref C obj, ref T val) if(is(T == struct)) 197 { 198 loopMembersImpl!T(obj , val); 199 } 200 201 void loopMembers(C, T)(auto ref C obj, ref T val) if(is(T == class)) 202 { 203 204 static if(is (C == BinarySerializer)) 205 { 206 if (val is null) 207 { 208 obj.putRaw(NULL); 209 return; 210 } 211 //assert(val !is null, "null value cannot be serialised"); 212 } 213 214 static if (is (C == BinaryDeserializer)) 215 { 216 if (obj.isNullObj) 217 { 218 val = null; 219 return; 220 } 221 } 222 223 static if(is(typeof(() { val = new T; }))) { 224 if(val is null) val = new T; 225 } else { 226 } 227 228 obj.putClass(val); 229 } 230 231 232 233 void loopMembersImpl(T, C, VT) (auto ref C obj, ref VT val) 234 { 235 foreach(member; __traits(derivedMembers, T)) { 236 enum isMemberVariable = is(typeof(() { 237 __traits(getMember, val, member) = __traits(getMember, val, member).init; 238 })); 239 static if(isMemberVariable) { 240 specifyAggregateMember!member(obj , val); 241 } 242 } 243 } 244 245 void specifyAggregateMember(string member, C, T)(auto ref C obj, ref T val) 246 { 247 import std.meta: staticIndexOf; 248 enum NoCereal; 249 enum noCerealIndex = staticIndexOf!(NoCereal, __traits(getAttributes,__traits(getMember, val, member))); 250 static if(noCerealIndex == -1) { 251 specifyMember!member(obj, val); 252 } 253 } 254 255 void specifyMember(string member, C, T)(auto ref C obj, ref T val) 256 { 257 specify( obj , __traits(getMember, val, member)); 258 } 259 260 void specifyBaseClass(C, T)(auto ref C obj, ref T val) if(is(T == class)) 261 { 262 foreach(base; BaseTypeTuple!T) 263 { 264 loopMembersImpl!base(obj ,val); 265 } 266 } 267 268 269 void specifyClass(C, T)(auto ref C obj, ref T val) if(is(T == class)) 270 { 271 specifyBaseClass(obj, val); 272 loopMembersImpl!T(obj, val); 273 } 274 275 void checkDecerealiser(T)() { 276 //static assert(T.type == CerealType.ReadBytes); 277 auto dec = T(); 278 ulong bl = dec.bytesLeft; 279 } 280 281 enum isDecerealiser(T) = (is (T == BinaryDeserializer) && is(typeof(checkDecerealiser!T))) ;