comparison orange/serialization/Serializer.d @ 0:f7b078e85f7f

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