1 module treeserial; 2 3 import std.traits; 4 import std.meta; 5 import std.bitmanip; 6 7 import std.algorithm; 8 import std.range; 9 10 struct NoLength { 11 bool value = true; 12 } 13 struct LengthType(T) { 14 alias Type = T; 15 } 16 17 struct CastType(T) { 18 alias Type = T; 19 } 20 21 struct ElementAttributes(Attribs...) { 22 alias Attributes = Attribs; 23 } 24 25 alias DefaultAttributes = AliasSeq!(NoLength(false), LengthType!ushort); 26 27 28 template Serializer(Attributes_...) { 29 alias Attributes = AliasSeq!(DefaultAttributes, Attributes_); 30 31 template Subserializer(MoreAttributes_...) { 32 alias Subserializer = Serializer!(Attributes_, MoreAttributes_); 33 } 34 alias Subdeserializer = Subserializer; 35 36 template isAttribute(alias T) { 37 enum isAttribute = Filter!(isDesiredUDA!T, Attributes).length > 0; 38 } 39 template GetAttributeType(alias T) { 40 alias GetAttributeType = Filter!(isDesiredUDA!T, Attributes)[$-1].Type; 41 } 42 template getAttributeValue(alias T) { 43 static if (is(Filter!(isDesiredUDA!T, Attributes)[$-1]))// For if the struct is not created but referencing the type: instantiate it, and use the default. 44 enum getAttributeValue = Filter!(isDesiredUDA!T, Attributes)[$-1]().value; 45 else 46 enum getAttributeValue = Filter!(isDesiredUDA!T, Attributes)[$-1].value; 47 } 48 template GetAttributes(alias T) { 49 template Get(alias EA) { 50 alias Get = EA.Attributes; 51 } 52 alias GetAttributes = staticMap!(Get, Filter!(isDesiredUDA!T, Attributes)); 53 } 54 template FilterOut_(alias T) { 55 alias FilterOut_ = Filter!(templateNot!(isDesiredUDA!T), Attributes_); 56 } 57 58 static if (isAttribute!CastType) { 59 ubyte[] serialize(T)(T data) if (__traits(compiles, cast(GetAttributeType!CastType) rvalueOf!T) && serializable!(GetAttributeType!CastType)) { 60 return Serializer!(FilterOut_!CastType).serialize(cast(GetAttributeType!CastType) data); 61 } 62 T deserialize(T)(ref const(ubyte)[] data) if (__traits(compiles, cast(T) rvalueOf!(GetAttributeType!CastType)) && deserializable!(GetAttributeType!CastType)) { 63 return cast(T) Serializer!(FilterOut_!CastType).deserialize!(GetAttributeType!CastType)(data); 64 } 65 } 66 else { 67 ubyte[] serialize(T)(T data) if(isIntegral!T || isSomeChar!T || isBoolean!T || isFloatOrDouble!T) { 68 return nativeToLittleEndian(data).dup; 69 } 70 ubyte[] serialize(T)(T data) if(isDynamicArray!T) { 71 alias Serializer_ = Serializer!(FilterOut_!ElementAttributes, GetAttributes!ElementAttributes); 72 static if (getAttributeValue!NoLength) 73 return data.map!(Serializer_.serialize).joiner.array; 74 else 75 return serialize(cast(GetAttributeType!LengthType) data.length) ~ data.map!(Serializer_.serialize).joiner.array; 76 } 77 78 T deserialize(T)(ref const(ubyte)[] data) if (isIntegral!T || isSomeChar!T || isBoolean!T || isFloatOrDouble!T) { 79 scope (success) 80 data = data[T.sizeof..$]; 81 return littleEndianToNative!T(data[0..T.sizeof]); 82 } 83 T deserialize(T)(ref const(ubyte)[] data) if (isDynamicArray!T) { 84 alias Serializer_ = Serializer!(FilterOut_!ElementAttributes, GetAttributes!ElementAttributes); 85 static if (getAttributeValue!NoLength) 86 return repeat(null).map!(_=>Serializer_.deserialize!(ForeachType!T)(data)).until!((lazy _)=>data.length==0).array; 87 else 88 return repeat(null, deserialize!(GetAttributeType!LengthType)(data)).map!(_=>Serializer_.deserialize!(ForeachType!T)(data)).array; 89 } 90 } 91 } 92 alias Deserializer = Serializer; 93 template serialize(Attributes...) { 94 alias serialize = Serializer!Attributes.serialize; 95 } 96 template deserialize(T, Attributes...) { 97 alias deserialize = Deserializer!Attributes.deserialize!T; 98 } 99 100 template serializable(T) { 101 enum serializable = __traits(compiles, rvalueOf!T.serialize); 102 } 103 template serializable(alias v) { 104 enum serializable = __traits(compiles, v.serialize); 105 } 106 template deserializable(T) { 107 enum deserializable = __traits(compiles, deserialize!T(lvalueOf!(const(ubyte)[]))); 108 } 109 110 /// Copied from phobas/std/bitmanip 111 private template isFloatOrDouble(T) 112 { 113 enum isFloatOrDouble = isFloatingPoint!T && 114 !is(Unqual!(FloatingPointTypeOf!T) == real); 115 } 116 117 118 @("number") 119 unittest { 120 { 121 int data = 5; 122 const(ubyte)[] bytes = serialize(data); 123 assert(bytes == [5,0,0,0] || bytes == [0,0,0,5]); 124 assert(bytes.deserialize!(typeof(data)) == data); 125 } 126 { 127 ushort data = 5; 128 const(ubyte)[] bytes = serialize(data); 129 assert(bytes == [5,0] || bytes == [0,5]); 130 assert(bytes.deserialize!(typeof(data)) == data); 131 } 132 } 133 @("cast type") 134 unittest { 135 { 136 int data = 5; 137 alias Serializer_ = Serializer!(CastType!byte); 138 const(ubyte)[] bytes = Serializer_.serialize(data); 139 assert(bytes == [5]); 140 assert(Serializer_.deserialize!(typeof(data))(bytes) == data); 141 } 142 } 143 @("array") 144 unittest { 145 { 146 int[] data = [1,2]; 147 const(ubyte)[] bytes = serialize(data); 148 assert(bytes == [2,0, 1,0,0,0, 2,0,0,0] || bytes == [0,2, 0,0,0,1, 0,0,0,2]); 149 assert(bytes.deserialize!(typeof(data)) == data); 150 } 151 // LengthType 152 { 153 int[] data = [1,2]; 154 alias Serializer_ = Serializer!(LengthType!uint); 155 const(ubyte)[] bytes = Serializer_.serialize(data); 156 assert(bytes == [2,0,0,0, 1,0,0,0, 2,0,0,0] || bytes == [0,0,0,2, 0,0,0,1, 0,0,0,2]); 157 assert(Serializer_.deserialize!(typeof(data))(bytes) == data); 158 } 159 // NoLength 160 { 161 int[] data = [1,2]; 162 alias Serializer_ = Serializer!(NoLength); 163 const(ubyte)[] bytes = Serializer_.serialize(data); 164 assert(bytes == [1,0,0,0, 2,0,0,0] || bytes == [0,0,0,1, 0,0,0,2]); 165 assert(Serializer_.deserialize!(typeof(data))(bytes) == data); 166 } 167 // ElementAttributes 168 { 169 int[] data = [1,2]; 170 alias Serializer_ = Serializer!(ElementAttributes!(CastType!ubyte)); 171 const(ubyte)[] bytes = Serializer_.serialize(data); 172 assert(bytes == [2,0, 1,2] || bytes == [0,2, 1,2]); 173 assert(Serializer_.deserialize!(typeof(data))(bytes) == data); 174 } 175 // Nested & ElementAttributes 176 { 177 int[][] data = [[1,2],[3,4]]; 178 alias Serializer_ = Serializer!(LengthType!ubyte, ElementAttributes!(ElementAttributes!(CastType!ubyte))); 179 const(ubyte)[] bytes = Serializer_.serialize(data); 180 assert(bytes == [2, 2,1,2, 2,3,4]); 181 assert(Serializer_.deserialize!(typeof(data))(bytes) == data); 182 } 183 } 184 185 /// Copied from std.traits 186 private template isDesiredUDA(alias attribute) 187 { 188 template isDesiredUDA(alias toCheck) 189 { 190 static if (is(typeof(attribute)) && !__traits(isTemplate, attribute)) 191 { 192 static if (__traits(compiles, toCheck == attribute)) 193 enum isDesiredUDA = toCheck == attribute; 194 else 195 enum isDesiredUDA = false; 196 } 197 else static if (is(typeof(toCheck))) 198 { 199 static if (__traits(isTemplate, attribute)) 200 enum isDesiredUDA = isInstanceOf!(attribute, typeof(toCheck)); 201 else 202 enum isDesiredUDA = is(typeof(toCheck) == attribute); 203 } 204 else static if (__traits(isTemplate, attribute)) 205 enum isDesiredUDA = isInstanceOf!(attribute, toCheck); 206 else 207 enum isDesiredUDA = is(toCheck == attribute); 208 } 209 } 210