Mercurial > projects > orange
annotate orange/serialization/Serializer.d @ 20:9a575087b961
Added support for slices. Strings and arrays are now treated as references.
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Mon, 04 Oct 2010 18:27:21 +0200 |
parents | 3d42ea434d46 |
children | b51e953f79eb |
rev | line source |
---|---|
0 | 1 /** |
2 * Copyright: Copyright (c) 2010 Jacob Carlborg. | |
3 * Authors: Jacob Carlborg | |
4 * Version: Initial created: Jan 26, 2010 | |
5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) | |
6 */ | |
7 module orange.serialization.Serializer; | |
8 | |
9 version (Tango) | |
9
99c52d46822a
Serialization works now with D2, deserialization still doesn't work
Jacob Carlborg <doob@me.com>
parents:
8
diff
changeset
|
10 import tango.util.Convert : to, ConversionException; |
99c52d46822a
Serialization works now with D2, deserialization still doesn't work
Jacob Carlborg <doob@me.com>
parents:
8
diff
changeset
|
11 |
99c52d46822a
Serialization works now with D2, deserialization still doesn't work
Jacob Carlborg <doob@me.com>
parents:
8
diff
changeset
|
12 else |
0 | 13 { |
9
99c52d46822a
Serialization works now with D2, deserialization still doesn't work
Jacob Carlborg <doob@me.com>
parents:
8
diff
changeset
|
14 import std.conv; |
99c52d46822a
Serialization works now with D2, deserialization still doesn't work
Jacob Carlborg <doob@me.com>
parents:
8
diff
changeset
|
15 alias ConvError ConversionException; |
0 | 16 } |
17 | |
18 import orange.serialization._; | |
19 import orange.serialization.archives._; | |
20 import orange.util._; | |
21 | |
22 private | |
23 { | |
24 alias orange.util.CTFE.contains ctfeContains; | |
20
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
25 |
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
26 enum Mode |
0 | 27 { |
28 serializing, | |
29 deserializing | |
30 } | |
31 | |
32 alias Mode.serializing serializing; | |
33 alias Mode.deserializing deserializing; | |
34 } | |
35 | |
36 class Serializer (ArchiveType : IArchive) | |
37 { | |
38 static assert(isArchive!(ArchiveType), format!(`The type "`, ArchiveType, `" does not implement the necessary methods to be an archive.`)); | |
39 | |
18
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
40 alias ArchiveType.ErrorCallback ErrorCallback; |
20
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
41 alias ArchiveType.DataType DataType; |
18
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
42 |
0 | 43 private |
44 { | |
45 ArchiveType archive; | |
46 | |
47 RegisterBase[string] serializers; | |
48 RegisterBase[string] deserializers; | |
49 | |
50 size_t keyCounter; | |
51 | |
52 bool hasBegunSerializing; | |
53 bool hasBegunDeserializing; | |
18
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
54 |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
55 void delegate (ArchiveException exception, DataType[] data) throwOnErrorCallback; |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
56 void delegate (ArchiveException exception, DataType[] data) doNothingOnErrorCallback; |
0 | 57 } |
58 | |
59 this () | |
60 { | |
61 archive = new ArchiveType; | |
18
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
62 |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
63 throwOnErrorCallback = (ArchiveException exception, DataType[] data) { throw exception; }; |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
64 doNothingOnErrorCallback = (ArchiveException exception, DataType[] data) { /* do nothing */ }; |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
65 |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
66 setThrowOnErrorCallback(); |
0 | 67 } |
68 | |
69 void registerSerializer (T) (string type, void delegate (T, Serializer, DataType) dg) | |
70 { | |
71 serializers[type] = toSerializeRegisterWrapper(dg); | |
72 } | |
73 | |
74 void registerSerializer (T) (string type, void function (T, Serializer, DataType) func) | |
75 { | |
76 serializers[type] = toSerializeRegisterWrapper(func); | |
77 } | |
78 | |
79 void registerDeserializer (T) (string type, void delegate (ref T, Serializer, DataType) dg) | |
80 { | |
81 deserializers[type] = toDeserializeRegisterWrapper(dg); | |
82 } | |
83 | |
84 void registerDeserializer (T) (string type, void function (ref T, Serializer, DataType) func) | |
85 { | |
86 deserializers[type] = toDeserializeRegisterWrapper(func); | |
87 } | |
88 | |
89 void reset () | |
90 { | |
91 hasBegunSerializing = false; | |
92 hasBegunDeserializing = false; | |
93 resetCounters(); | |
94 | |
95 archive.reset; | |
96 } | |
97 | |
18
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
98 ErrorCallback errorCallback () |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
99 { |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
100 return archive.errorCallback; |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
101 } |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
102 |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
103 ErrorCallback errorCallback (ErrorCallback errorCallback) |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
104 { |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
105 return archive.errorCallback = errorCallback; |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
106 } |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
107 |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
108 void setThrowOnErrorCallback () |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
109 { |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
110 errorCallback = throwOnErrorCallback; |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
111 } |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
112 |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
113 void setDoNothingOnErrorCallback () |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
114 { |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
115 errorCallback = doNothingOnErrorCallback; |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
116 } |
3d42ea434d46
Added an error callback. Fixes #3 and #4.
Jacob Carlborg <doob@me.com>
parents:
17
diff
changeset
|
117 |
0 | 118 DataType serialize (T) (T value, DataType key = null) |
119 { | |
120 if (!hasBegunSerializing) | |
121 hasBegunSerializing = true; | |
122 | |
20
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
123 serializeInternal(value, key); |
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
124 archive.postProcess; |
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
125 |
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
126 return archive.data; |
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
127 } |
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
128 |
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
129 private void serializeInternal (T) (T value, DataType key = null) |
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
130 { |
0 | 131 if (!key) |
132 key = nextKey; | |
133 | |
134 archive.beginArchiving(); | |
135 | |
136 static if (isTypeDef!(T)) | |
137 serializeTypeDef(value, key); | |
138 | |
139 static if (isObject!(T)) | |
140 serializeObject(value, key); | |
141 | |
142 else static if (isStruct!(T)) | |
143 serializeStruct(value, key); | |
144 | |
145 else static if (isString!(T)) | |
146 serializeString(value, key); | |
147 | |
148 else static if (isArray!(T)) | |
149 serializeArray(value, key); | |
150 | |
151 else static if (isAssociativeArray!(T)) | |
152 serializeAssociativeArray(value, key); | |
153 | |
154 else static if (isPrimitive!(T)) | |
155 serializePrimitive(value, key); | |
156 | |
157 else static if (isPointer!(T)) | |
158 { | |
159 static if (isFunctionPointer!(T)) | |
2 | 160 goto error; |
0 | 161 |
162 else | |
163 serializePointer(value, key); | |
2 | 164 } |
0 | 165 |
166 else static if (isEnum!(T)) | |
167 serializeEnum(value, key); | |
168 | |
169 else | |
2 | 170 { |
171 error: | |
172 throw new SerializationException(format!(`The type "`, T, `" cannot be serialized.`), __FILE__, __LINE__); | |
173 } | |
0 | 174 } |
175 | |
176 private void serializeObject (T) (T value, DataType key) | |
2 | 177 { |
0 | 178 triggerEvents(serializing, value, { |
179 archive.archive(value, key, { | |
180 auto runtimeType = value.classinfo.name; | |
181 | |
182 if (runtimeType in serializers) | |
183 { | |
184 auto wrapper = getSerializerWrapper!(T)(runtimeType); | |
185 wrapper(value, this, key); | |
186 } | |
187 | |
17
c4e7e64ffb67
Changed toData/fromData to take an instance of the serializer instead of the archive.
Jacob Carlborg <doob@me.com>
parents:
16
diff
changeset
|
188 else static if (isSerializable!(T, Serializer)) |
0 | 189 value.toData(this, key); |
190 | |
191 else | |
192 { | |
193 if (isBaseClass(value)) | |
194 throw new SerializationException(`The object of the static type "` ~ T.stringof ~ `" have a different runtime type (` ~ runtimeType ~ `) and therefore needs to register a serializer for its type "` ~ runtimeType ~ `".`, __FILE__, __LINE__); | |
195 | |
2 | 196 objectStructSerializeHelper(value); |
0 | 197 } |
198 }); | |
199 }); | |
200 } | |
201 | |
202 private void serializeStruct (T) (T value, DataType key) | |
203 { | |
204 triggerEvents(serializing, value, { | |
205 archive.archive(value, key, { | |
206 auto type = toDataType(T.stringof); | |
207 | |
208 if (type in serializers) | |
209 { | |
210 auto wrapper = getSerializerWrapper!(T)(type); | |
211 wrapper(value, this, key); | |
212 } | |
213 | |
214 else | |
215 { | |
17
c4e7e64ffb67
Changed toData/fromData to take an instance of the serializer instead of the archive.
Jacob Carlborg <doob@me.com>
parents:
16
diff
changeset
|
216 static if (isSerializable!(T, Serializer)) |
0 | 217 value.toData(this, key); |
218 | |
219 else | |
2 | 220 objectStructSerializeHelper(value); |
0 | 221 } |
222 }); | |
223 }); | |
224 } | |
225 | |
226 private void serializeString (T) (T value, DataType key) | |
227 { | |
228 archive.archive(value, key); | |
229 } | |
230 | |
231 private void serializeArray (T) (T value, DataType key) | |
20
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
232 { |
0 | 233 archive.archive(value, key, { |
234 foreach (i, e ; value) | |
20
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
235 serializeInternal(e, toDataType(i)); |
0 | 236 }); |
237 } | |
238 | |
239 private void serializeAssociativeArray (T) (T value, DataType key) | |
240 { | |
241 archive.archive(value, key, { | |
242 foreach(k, v ; value) | |
20
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
243 serializeInternal(v, toDataType(k)); |
0 | 244 }); |
245 } | |
246 | |
247 private void serializePointer (T) (T value, DataType key) | |
248 { | |
249 archive.archive(value, key, { | |
250 if (key in serializers) | |
251 { | |
252 auto wrapper = getSerializerWrapper!(T)(key); | |
253 wrapper(value, this, key); | |
254 } | |
255 | |
17
c4e7e64ffb67
Changed toData/fromData to take an instance of the serializer instead of the archive.
Jacob Carlborg <doob@me.com>
parents:
16
diff
changeset
|
256 else static if (isSerializable!(T, Serializer)) |
0 | 257 value.toData(this, key); |
258 | |
259 else | |
260 { | |
261 static if (isVoid!(BaseTypeOfPointer!(T))) | |
262 throw new SerializationException(`The value with the key "` ~ to!(string)(key) ~ `"` ~ format!(` of the type "`, T, `" cannot be serialized on its own, either implement orange.serialization.Serializable.isSerializable or register a serializer.`), __FILE__, __LINE__); | |
263 | |
264 else | |
20
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
265 serializeInternal(*value, key); |
0 | 266 } |
267 }); | |
268 } | |
269 | |
270 private void serializeEnum (T) (T value, DataType key) | |
271 { | |
272 archive.archive(value, key); | |
273 } | |
274 | |
275 private void serializePrimitive (T) (T value, DataType key) | |
276 { | |
277 archive.archive(value, key); | |
278 } | |
279 | |
280 private void serializeTypeDef (T) (T value, DataType key) | |
281 { | |
282 archive.archive(value, key, { | |
20
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
283 serializeInternal!(BaseTypeOfTypeDef!(T))(value, key); |
0 | 284 }); |
285 } | |
286 | |
287 T deserialize (T) (DataType data, DataType key = null) | |
288 { | |
289 if (hasBegunSerializing && !hasBegunDeserializing) | |
290 resetCounters(); | |
291 | |
292 if (!hasBegunDeserializing) | |
293 hasBegunDeserializing = true; | |
294 | |
295 if (!key) | |
296 key = nextKey; | |
297 | |
298 archive.beginUnarchiving(data); | |
299 return deserializeInternal!(T)(key); | |
300 } | |
301 | |
302 private T deserializeInternal (T) (DataType key) | |
303 { | |
304 static if (isTypeDef!(T)) | |
305 return deserializeTypeDef!(T)(key); | |
306 | |
307 else static if (isObject!(T)) | |
308 return deserializeObject!(T)(key); | |
309 | |
310 else static if (isStruct!(T)) | |
311 return deserializeStruct!(T)(key); | |
312 | |
313 else static if (isString!(T)) | |
314 return deserializeString!(T)(key); | |
315 | |
316 else static if (isArray!(T)) | |
317 return deserializeArray!(T)(key); | |
318 | |
319 else static if (isAssociativeArray!(T)) | |
320 return deserializeAssociativeArray!(T)(key); | |
321 | |
322 else static if (isPrimitive!(T)) | |
323 return deserializePrimitive!(T)(key); | |
324 | |
325 else static if (isPointer!(T)) | |
2 | 326 { |
327 static if (isFunctionPointer!(T)) | |
328 goto error; | |
329 | |
0 | 330 return deserializePointer!(T)(key); |
2 | 331 } |
0 | 332 |
333 else static if (isEnum!(T)) | |
334 return deserializeEnum!(T)(key); | |
335 | |
336 else | |
2 | 337 { |
338 error: | |
339 throw new SerializationException(format!(`The type "`, T, `" cannot be deserialized.`), __FILE__, __LINE__); | |
340 } | |
0 | 341 } |
342 | |
343 private T deserializeObject (T) (DataType key) | |
344 { | |
2 | 345 T value = archive.unarchive!(T)(key, (T value) { |
0 | 346 triggerEvents(deserializing, value, { |
347 auto runtimeType = value.classinfo.name; | |
348 | |
349 if (runtimeType in deserializers) | |
350 { | |
351 auto wrapper = getDeserializerWrapper!(T)(runtimeType); | |
352 wrapper(value, this, key); | |
353 } | |
354 | |
17
c4e7e64ffb67
Changed toData/fromData to take an instance of the serializer instead of the archive.
Jacob Carlborg <doob@me.com>
parents:
16
diff
changeset
|
355 else static if (isSerializable!(T, Serializer)) |
0 | 356 value.fromData(this, key); |
357 | |
358 else | |
359 { | |
360 if (isBaseClass(value)) | |
361 throw new SerializationException(`The object of the static type "` ~ T.stringof ~ `" have a different runtime type (` ~ runtimeType ~ `) and therefore needs to register a deserializer for its type "` ~ runtimeType ~ `".`, __FILE__, __LINE__); | |
362 | |
2 | 363 objectStructDeserializeHelper(value); |
0 | 364 } |
365 }); | |
366 | |
367 return value; | |
368 }); | |
369 | |
370 return value; | |
371 } | |
372 | |
373 private T deserializeStruct (T) (DataType key) | |
374 { | |
375 return archive.unarchive!(T)(key, (T value) { | |
376 triggerEvents(deserializing, value, { | |
377 auto type = toDataType(T.stringof); | |
378 | |
379 if (type in deserializers) | |
380 { | |
381 auto wrapper = getDeserializerWrapper!(T)(type); | |
382 wrapper(value, this, key); | |
383 } | |
384 | |
385 else | |
386 { | |
17
c4e7e64ffb67
Changed toData/fromData to take an instance of the serializer instead of the archive.
Jacob Carlborg <doob@me.com>
parents:
16
diff
changeset
|
387 static if (isSerializable!(T, Serializer)) |
0 | 388 value.fromData(this, key); |
389 | |
390 else | |
2 | 391 objectStructDeserializeHelper(value); |
0 | 392 } |
393 }); | |
394 | |
395 return value; | |
396 }); | |
397 } | |
398 | |
399 private T deserializeString (T) (DataType key) | |
400 { | |
401 return archive.unarchive!(T)(key); | |
402 } | |
403 | |
404 private T deserializeArray (T) (DataType key) | |
405 { | |
406 return archive.unarchive!(T)(key, (T value) { | |
407 foreach (i, ref e ; value) | |
14
6e454595b203
Fixed (de)serializing of arrays and associative arrays.
Jacob Carlborg <doob@me.com>
parents:
9
diff
changeset
|
408 e = deserializeInternal!(typeof(e))(toDataType(i)); |
0 | 409 |
410 return value; | |
411 }); | |
412 } | |
413 | |
414 private T deserializeAssociativeArray (T) (DataType key) | |
415 { | |
416 return archive.unarchive!(T)(key, (T value) { | |
417 foreach (k, v ; archive.unarchiveAssociativeArrayVisitor!(T)) | |
418 value[k] = v; | |
419 | |
420 return value; | |
421 }); | |
422 } | |
423 | |
424 private T deserializePointer (T) (DataType key) | |
425 { | |
426 return archive.unarchive!(T)(key, (T value) { | |
427 if (key in deserializers) | |
428 { | |
429 auto wrapper = getDeserializerWrapper!(T)(key); | |
430 wrapper(value, this, key); | |
431 } | |
432 | |
17
c4e7e64ffb67
Changed toData/fromData to take an instance of the serializer instead of the archive.
Jacob Carlborg <doob@me.com>
parents:
16
diff
changeset
|
433 else static if (isSerializable!(T, Serializer)) |
0 | 434 value.fromData(this, key); |
435 | |
436 else | |
437 { | |
438 static if (isVoid!(BaseTypeOfPointer!(T))) | |
439 throw new SerializationException(`The value with the key "` ~ to!(string)(key) ~ `"` ~ format!(` of the type "`, T, `" cannot be deserialized on its own, either implement orange.serialization.Serializable.isSerializable or register a deserializer.`), __FILE__, __LINE__); | |
440 | |
441 else | |
442 *value = deserializeInternal!(BaseTypeOfPointer!(T))(key); | |
443 } | |
444 | |
445 return value; | |
446 }); | |
447 } | |
448 | |
449 private T deserializeEnum (T) (DataType key) | |
450 { | |
451 return archive.unarchive!(T)(key); | |
452 } | |
453 | |
454 private T deserializePrimitive (T) (DataType key) | |
455 { | |
456 return archive.unarchive!(T)(key); | |
457 } | |
458 | |
459 private T deserializeTypeDef (T) (DataType key) | |
460 { | |
461 return archive.unarchive!(T)(key, (T value) { | |
462 return deserializeInternal!(BaseTypeOfTypeDef!(T))(key); | |
463 }); | |
464 } | |
465 | |
3 | 466 private void objectStructSerializeHelper (T) (ref T value) |
467 { | |
468 static assert(isStruct!(T) || isObject!(T), format!(`The given value of the type "`, T, `" is not a valid type, the only valid types for this method are objects and structs.`)); | |
8 | 469 const nonSerializedFields = collectAnnotations!(nonSerializedField, T); |
3 | 470 |
471 foreach (i, dummy ; typeof(T.tupleof)) | |
472 { | |
473 const field = nameOfFieldAt!(T, i); | |
474 | |
475 static if (!internalFields.ctfeContains(field) && !nonSerializedFields.ctfeContains(field)) | |
476 { | |
477 alias typeof(T.tupleof[i]) Type; | |
478 Type v = value.tupleof[i]; | |
20
9a575087b961
Added support for slices. Strings and arrays are now treated as references.
Jacob Carlborg <doob@me.com>
parents:
18
diff
changeset
|
479 serializeInternal(v, toDataType(field)); |
3 | 480 } |
481 } | |
2 | 482 |
4
470ab5270d0c
Simplified the implementation of RegisterWrapper. Fixed: the base class of an object was not serialized
Jacob Carlborg <doob@me.com>
parents:
3
diff
changeset
|
483 static if (isObject!(T) && !is(T == Object)) |
470ab5270d0c
Simplified the implementation of RegisterWrapper. Fixed: the base class of an object was not serialized
Jacob Carlborg <doob@me.com>
parents:
3
diff
changeset
|
484 serializeBaseTypes(value); |
3 | 485 } |
486 | |
487 private void objectStructDeserializeHelper (T) (ref T value) | |
488 { | |
489 static assert(isStruct!(T) || isObject!(T), format!(`The given value of the type "`, T, `" is not a valid type, the only valid types for this method are objects and structs.`)); | |
8 | 490 const nonSerializedFields = collectAnnotations!(nonSerializedField, T); |
3 | 491 |
492 foreach (i, dummy ; typeof(T.tupleof)) | |
493 { | |
494 const field = nameOfFieldAt!(T, i); | |
495 | |
496 static if (!internalFields.ctfeContains(field) && !nonSerializedFields.ctfeContains(field)) | |
497 { | |
498 alias TypeOfField!(T, field) Type; | |
499 auto fieldValue = deserializeInternal!(Type)(toDataType(field)); | |
500 value.tupleof[i] = fieldValue; | |
501 } | |
502 } | |
4
470ab5270d0c
Simplified the implementation of RegisterWrapper. Fixed: the base class of an object was not serialized
Jacob Carlborg <doob@me.com>
parents:
3
diff
changeset
|
503 |
470ab5270d0c
Simplified the implementation of RegisterWrapper. Fixed: the base class of an object was not serialized
Jacob Carlborg <doob@me.com>
parents:
3
diff
changeset
|
504 static if (isObject!(T) && !is(T == Object)) |
470ab5270d0c
Simplified the implementation of RegisterWrapper. Fixed: the base class of an object was not serialized
Jacob Carlborg <doob@me.com>
parents:
3
diff
changeset
|
505 deserializeBaseTypes(value); |
0 | 506 } |
507 | |
2 | 508 private void serializeBaseTypes (T : Object) (T value) |
0 | 509 { |
510 alias BaseTypeTupleOf!(T)[0] Base; | |
511 | |
512 static if (!is(Base == Object)) | |
513 { | |
514 archive.archiveBaseClass!(Base)(nextKey); | |
4
470ab5270d0c
Simplified the implementation of RegisterWrapper. Fixed: the base class of an object was not serialized
Jacob Carlborg <doob@me.com>
parents:
3
diff
changeset
|
515 Base base = value; |
470ab5270d0c
Simplified the implementation of RegisterWrapper. Fixed: the base class of an object was not serialized
Jacob Carlborg <doob@me.com>
parents:
3
diff
changeset
|
516 objectStructSerializeHelper(base); |
0 | 517 } |
518 } | |
519 | |
2 | 520 private void deserializeBaseTypes (T : Object) (T value) |
0 | 521 { |
522 alias BaseTypeTupleOf!(T)[0] Base; | |
523 | |
524 static if (!is(Base == Object)) | |
525 { | |
526 archive.unarchiveBaseClass!(Base)(nextKey); | |
4
470ab5270d0c
Simplified the implementation of RegisterWrapper. Fixed: the base class of an object was not serialized
Jacob Carlborg <doob@me.com>
parents:
3
diff
changeset
|
527 Base base = value; |
470ab5270d0c
Simplified the implementation of RegisterWrapper. Fixed: the base class of an object was not serialized
Jacob Carlborg <doob@me.com>
parents:
3
diff
changeset
|
528 objectStructDeserializeHelper(base); |
0 | 529 } |
530 } | |
531 | |
15
9f6064f9505a
Changed from archive to serializer in the register wrappers.
Jacob Carlborg <doob@me.com>
parents:
14
diff
changeset
|
532 private SerializeRegisterWrapper!(T, Serializer) getSerializerWrapper (T) (string type) |
0 | 533 { |
15
9f6064f9505a
Changed from archive to serializer in the register wrappers.
Jacob Carlborg <doob@me.com>
parents:
14
diff
changeset
|
534 auto wrapper = cast(SerializeRegisterWrapper!(T, Serializer)) serializers[type]; |
0 | 535 |
536 if (wrapper) | |
537 return wrapper; | |
538 | |
539 assert(false, "throw exception here"); | |
540 } | |
541 | |
15
9f6064f9505a
Changed from archive to serializer in the register wrappers.
Jacob Carlborg <doob@me.com>
parents:
14
diff
changeset
|
542 private DeserializeRegisterWrapper!(T, Serializer) getDeserializerWrapper (T) (string type) |
0 | 543 { |
15
9f6064f9505a
Changed from archive to serializer in the register wrappers.
Jacob Carlborg <doob@me.com>
parents:
14
diff
changeset
|
544 auto wrapper = cast(DeserializeRegisterWrapper!(T, Serializer)) deserializers[type]; |
0 | 545 |
546 if (wrapper) | |
547 return wrapper; | |
548 | |
549 assert(false, "throw exception here"); | |
550 } | |
551 | |
16
091ff1b263db
Missed some in the previous commit.
Jacob Carlborg <doob@me.com>
parents:
15
diff
changeset
|
552 private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void delegate (T, Serializer, DataType) dg) |
0 | 553 { |
16
091ff1b263db
Missed some in the previous commit.
Jacob Carlborg <doob@me.com>
parents:
15
diff
changeset
|
554 return new SerializeRegisterWrapper!(T, Serializer)(dg); |
0 | 555 } |
556 | |
16
091ff1b263db
Missed some in the previous commit.
Jacob Carlborg <doob@me.com>
parents:
15
diff
changeset
|
557 private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void function (T, Serializer, DataType) func) |
0 | 558 { |
16
091ff1b263db
Missed some in the previous commit.
Jacob Carlborg <doob@me.com>
parents:
15
diff
changeset
|
559 return new SerializeRegisterWrapper!(T, Serializer)(func); |
0 | 560 } |
561 | |
16
091ff1b263db
Missed some in the previous commit.
Jacob Carlborg <doob@me.com>
parents:
15
diff
changeset
|
562 private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void delegate (ref T, Serializer, DataType) dg) |
0 | 563 { |
16
091ff1b263db
Missed some in the previous commit.
Jacob Carlborg <doob@me.com>
parents:
15
diff
changeset
|
564 return new DeserializeRegisterWrapper!(T, Serializer)(dg); |
0 | 565 } |
566 | |
16
091ff1b263db
Missed some in the previous commit.
Jacob Carlborg <doob@me.com>
parents:
15
diff
changeset
|
567 private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void function (ref T, Serializer, DataType) func) |
0 | 568 { |
16
091ff1b263db
Missed some in the previous commit.
Jacob Carlborg <doob@me.com>
parents:
15
diff
changeset
|
569 return new DeserializeRegisterWrapper!(T, Serializer)(func); |
0 | 570 } |
571 | |
572 private DataType toDataType (T) (T value) | |
573 { | |
574 try | |
575 return to!(DataType)(value); | |
576 | |
577 catch (ConversionException e) | |
578 throw new SerializationException(e); | |
579 } | |
580 | |
581 private bool isBaseClass (T) (T value) | |
582 { | |
583 auto name = value.classinfo.name; | |
584 auto index = name.lastIndexOf('.'); | |
585 | |
586 return T.stringof != name[index + 1 .. $]; | |
587 } | |
588 | |
589 private DataType nextKey () | |
590 { | |
591 return toDataType(keyCounter++); | |
592 } | |
593 | |
594 private void resetCounters () | |
595 { | |
596 keyCounter = 0; | |
597 } | |
598 | |
599 private void triggerEvent (string name, T) (T value) | |
600 { | |
3 | 601 static assert (isObject!(T) || isStruct!(T), format!(`The given value of the type "`, T, `" is not a valid type, the only valid types for this method are objects and structs.`)); |
0 | 602 |
603 foreach (i, dummy ; typeof(T.tupleof)) | |
604 { | |
605 const field = nameOfFieldAt!(T, i); | |
606 | |
607 static if (field == name) | |
608 { | |
609 alias TypeOfField!(T, field) Type; | |
610 auto event = getValueOfField!(T, Type, field)(value); | |
611 event(value); | |
612 } | |
613 } | |
614 } | |
615 | |
616 private void triggerEvents (T) (Mode mode, T value, void delegate () dg) | |
617 { | |
618 if (mode == serializing) | |
619 triggerEvent!(onSerializingField)(value); | |
620 | |
621 else | |
622 triggerEvent!(onDeserializingField)(value); | |
623 | |
624 dg(); | |
625 | |
626 if (mode == serializing) | |
627 triggerEvent!(onSerializedField)(value); | |
628 | |
629 else | |
630 triggerEvent!(onDeserializedField)(value); | |
631 } | |
632 | |
8 | 633 private static string[] collectAnnotations (string name, T) () |
0 | 634 { |
3 | 635 static assert (isObject!(T) || isStruct!(T), format!(`The given value of the type "`, T, `" is not a valid type, the only valid types for this method are objects and structs.`)); |
0 | 636 |
637 string[] annotations; | |
638 | |
8 | 639 foreach (i, type ; typeof(T.tupleof)) |
0 | 640 { |
641 const field = nameOfFieldAt!(T, i); | |
642 | |
643 static if (field == name) | |
8 | 644 annotations ~= type.field; |
0 | 645 } |
646 | |
647 return annotations; | |
648 } | |
649 } |