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