1 module drmi.sbin; 2 3 import std.algorithm; 4 import std.array; 5 import std.bitmanip; 6 import std.traits; 7 import std.range; 8 9 alias pack = nativeToLittleEndian; 10 alias unpack = littleEndianToNative; 11 12 void sbinSerialize(T, R)(auto ref const T val, ref R r) 13 if (isOutputRange!(R, ubyte)) 14 { 15 static if (is(T : double) || is(T : long)) 16 r.put(val.pack[]); 17 else static if (isStaticArray!T) 18 foreach (v; val) sbinSerialize(v, r); 19 else static if (isSomeString!T) 20 { 21 r.put((cast(ulong)val.length).pack[]); 22 r.put(cast(ubyte[])val); 23 } 24 else static if (isDynamicArray!T) 25 { 26 r.put((cast(ulong)val.length).pack[]); 27 foreach (v; val) sbinSerialize(v, r); 28 } 29 else static if (is(T == struct) || isTypeTuple!T) 30 foreach (v; val.tupleof) sbinSerialize(v, r); 31 else 32 static assert(0, "unsupported type: " ~ T.stringof); 33 } 34 35 ubyte[] sbinSerialize(T)(auto ref const T val) 36 { 37 auto buf = appender!(ubyte[]); 38 sbinSerialize(val, buf); 39 return buf.data.dup; 40 } 41 42 Tb sbinDeserialize(Tb, Rb)(Rb r) 43 { 44 auto impl(T,R)(ref R r) 45 { 46 static if (is(T : double) || is(T : long)) 47 { 48 ubyte[T.sizeof] tmp; 49 foreach (ref v; tmp) 50 { 51 v = r.front; 52 r.popFront(); 53 } 54 return tmp.unpack!T; 55 } 56 else static if (isSomeString!T) 57 { 58 auto length = cast(size_t)impl!ulong(r); 59 auto tmp = new ubyte[](length); 60 foreach (ref v; tmp) 61 { 62 v = r.front; 63 r.popFront(); 64 } 65 return cast(T)tmp; 66 } 67 else static if (isStaticArray!T) 68 { 69 T ret; 70 foreach (ref v; ret) v = impl!(typeof(ret[0]))(r); 71 return ret; 72 } 73 else static if (isDynamicArray!T) 74 { 75 T ret; 76 ret.length = cast(size_t)impl!ulong(r); 77 foreach (ref v; ret) v = impl!(typeof(ret[0]))(r); 78 return ret; 79 } 80 else static if (is(T == struct) || isTypeTuple!T) 81 { 82 T ret; 83 foreach (i, ref v; ret.tupleof) 84 v = impl!(Unqual!(typeof(v)))(r); 85 return ret; 86 } 87 else 88 static assert(0, "unsupported type: " ~ T.stringof); 89 } 90 return impl!Tb(r); 91 } 92 93 unittest 94 { 95 auto a = 123; 96 assert(a.sbinSerialize.sbinDeserialize!int == a); 97 } 98 99 unittest 100 { 101 auto s = "hello world"; 102 assert(equal(s.sbinSerialize.sbinDeserialize!string, s)); 103 } 104 105 unittest 106 { 107 immutable(int[]) a = [1,2,3,2,3,2,1]; 108 assert(a.sbinSerialize.sbinDeserialize!(int[]) == a); 109 } 110 111 unittest 112 { 113 import std.array; 114 auto ap = appender!(ubyte[]); 115 116 struct Cell 117 { 118 ulong id; 119 float volt, temp; 120 ushort soc, soh; 121 string strData; 122 bool tr; 123 } 124 125 struct Line 126 { 127 ulong id; 128 float volt, curr; 129 Cell[] cells; 130 } 131 132 auto lines = [ 133 Line(123, 134 3.14, 2.17, 135 [ 136 Cell(1, 1.1, 2.2, 5, 8, "one", true), 137 Cell(2, 1.3, 2.5, 7, 9, "two"), 138 Cell(3, 1.5, 2.8, 3, 7, "three"), 139 ] 140 ), 141 Line(23, 142 31.4, 21.7, 143 [ 144 Cell(10, .11, .22, 50, 80, "1one1"), 145 Cell(20, .13, .25, 70, 90, "2two2", true), 146 Cell(30, .15, .28, 30, 70, "3three3"), 147 ] 148 ), 149 ]; 150 151 auto sdata = lines.sbinSerialize; 152 assert( equal(sdata.sbinDeserialize!(Line[]), lines)); 153 lines[0].cells[1].soh = 123; 154 assert(!equal(sdata.sbinDeserialize!(Line[]), lines)); 155 } 156 157 unittest 158 { 159 static void foo(int a=123, string b="hello") 160 { 161 162 } 163 auto a = ParameterDefaults!foo; 164 165 import std.typecons; 166 auto sa = tuple(a).sbinSerialize; 167 168 Parameters!foo b; 169 b = sa.sbinDeserialize!(typeof(tuple(b))); 170 assert(a == b); 171 }