1 /* 2 Copyright (c) 2017-2018 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.resource.serialization; 29 30 import std.traits; 31 import std.bitmanip; 32 33 import dlib.core.stream; 34 35 // Stream-based serialization and deserialization 36 37 struct Series(T, bool fixedSize = false) 38 { 39 union 40 { 41 T _value; 42 static if (isDynamicArray!T) 43 ubyte[] _bytes; 44 else 45 ubyte[T.sizeof] _bytes; 46 } 47 48 this(T val) 49 { 50 value = val; 51 } 52 53 T opAssign(T val) 54 { 55 return (value = val); 56 } 57 58 this(InputStream istrm) 59 { 60 readFrom(istrm); 61 } 62 63 @property T value(T v) 64 { 65 static if (isIntegral!T) 66 { 67 _bytes = nativeToLittleEndian!T(v); 68 } 69 else 70 _value = v; 71 return _value; 72 } 73 74 @property T value() 75 { 76 T res; 77 static if (isIntegral!T) 78 { 79 res = littleEndianToNative!T(_bytes); 80 } 81 else 82 res = _value; 83 return res; 84 } 85 86 size_t writeTo(OutputStream ostrm) 87 { 88 size_t n = 0; 89 static if (isDynamicArray!T) 90 { 91 n += Series!(uint)(cast(uint)_value.length).writeTo(ostrm); 92 foreach(v; _value) 93 n += Series!(Unqual!(typeof(v)))(v).writeTo(ostrm); 94 return n; 95 } 96 else 97 static if (is(T == struct) || is(T == class)) 98 { 99 static if (is(T == class)) 100 if (_value is null) 101 throw new Exception("null reference in input"); 102 103 // TODO: make automatic check 104 static if (is(T == struct) && fixedSize) 105 { 106 n = ostrm.writeBytes(_bytes.ptr, _bytes.length); 107 } 108 else 109 { 110 foreach(v; _value.tupleof) 111 n += Series!(typeof(v))(v).writeTo(ostrm); 112 } 113 return n; 114 } 115 else 116 { 117 return ostrm.writeBytes(_bytes.ptr, _bytes.length); 118 } 119 } 120 121 size_t readFrom(InputStream istrm) 122 { 123 static if (isSomeString!T) 124 { 125 uint len = Series!(uint)(istrm).value; 126 size_t pos = 4; 127 ubyte[] buff = new ubyte[len]; 128 istrm.fillArray(buff); 129 T str = cast(T)buff; 130 _value = str; 131 pos += len; 132 return pos; 133 } 134 else 135 static if (isDynamicArray!T) 136 { 137 uint len = Series!(uint)(istrm).value; 138 size_t pos = 4; 139 alias FT = ForeachType!T; 140 if (len == 0) 141 return pos; 142 143 _value = new FT[len]; 144 145 foreach(ref v; _value) 146 { 147 Series!(FT) se; 148 size_t s = se.readFrom(istrm); 149 v = se.value; 150 pos += s; 151 } 152 153 return pos; 154 } 155 else 156 static if (is(T == struct) || is(T == class)) 157 { 158 size_t pos = 0; 159 static if (is(T == class)) 160 if (_value is null) 161 throw new Exception("null reference in output"); 162 163 static if (is(T == struct) && fixedSize) 164 { 165 pos += istrm.readBytes(_bytes.ptr, T.sizeof); 166 } 167 else 168 foreach(ref v; _value.tupleof) 169 { 170 Series!(typeof(v)) se; 171 static if (is(typeof(v) == class)) 172 { 173 if (v is null) 174 throw new Exception("null reference in output"); 175 se._value = v; 176 } 177 size_t s = se.readFrom(istrm); 178 v = se.value; 179 pos += s; 180 } 181 182 return pos; 183 } 184 else 185 { 186 return istrm.readBytes(_bytes.ptr, T.sizeof); 187 } 188 } 189 } 190 191 T read(T, bool fixedSize = false)(InputStream istrm) 192 { 193 auto s = Series!(T, fixedSize)(istrm); 194 return s.value; 195 } 196 197 size_t write(T, bool fixedSize = false)(InputStream istrm, T val) 198 { 199 auto s = Series!(T, fixedSize)(val); 200 return s.writeTo(istrm); 201 } 202