1 /**
2  * Copyright: Copyright (c) 2010-2011 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 import std.conv;
10 import std.array;
11 
12 import orange.core.Attribute;
13 import orange.serialization._;
14 import orange.serialization.archives.Archive;
15 import orange.util._;
16 import orange.util.collection.Array;
17 
18 private
19 {
20     alias orange.util.CTFE.contains ctfeContains;
21 
22     enum Mode
23     {
24         serializing,
25         deserializing
26     }
27 
28     alias Mode.serializing serializing;
29     alias Mode.deserializing deserializing;
30 
31     private char toUpper () (char c)
32     {
33         if (c >= 'a' && c <= 'z')
34             return cast(char) (c - 32);
35 
36         return c;
37     }
38 }
39 
40 /**
41  * This class represents a serializer. It's the main interface to the (de)serialization
42  * process and it's this class that actually performs most of the (de)serialization.
43  *
44  * The serializer is the frontend in the serialization process, it's independent of the
45  * underlying archive type. It's responsible for collecting and tracking all values that
46  * should be (de)serialized. It's the serializer that adds keys and ID's to all values,
47  * keeps track of references to make sure that a given value (of reference type) is only
48  * (de)serialized once.
49  *
50  * The serializer is also responsible for breaking up types that the underlying archive
51  * cannot handle, into primitive types that archive know how to (de)serialize.
52  *
53  * Keys are used by the serializer to associate a name with a value. It's used to
54  * deserialize values independently of the order of the fields of a class or struct.
55  * They can also be used by the user to give a name to a value. Keys are unique within
56  * it's scope.
57  *
58  * ID's are an unique identifier associated with each serialized value. The serializer
59  * uses the ID's to track values when (de)serializing reference types. An ID is unique
60  * across the whole serialized data.
61  *
62  * Examples:
63  * ---
64  * import std.stdio;
65  * import orange.serialization._;
66  * import orange.serialization.archives._;
67  *
68  * class Foo
69  * {
70  *     int a;
71  * }
72  *
73  * void main ()
74  * {
75  *     auto archive = new XmlArchive!();
76  *     auto serializer = new Serializer;
77  *
78  *     auto foo = new Foo;
79  *     foo.a = 3;
80  *
81  *     serializer.serialize(foo);
82  *     auto foo2 = serializer.deserialize!(Foo)(archive.untypedData);
83  *
84  *     writeln(foo2.a); // prints "3"
85  *     assert(foo.a == foo2.a);
86  * }
87  * ---
88  */
89 class Serializer
90 {
91     /// The type of error callback.
92     alias Archive.ErrorCallback ErrorCallback;
93 
94     /// The type of the serialized data. This is an untyped format.
95     alias Archive.UntypedData Data;
96 
97     /// The type of an ID.
98     alias Archive.Id Id;
99 
100     /**
101      * This callback will be called when an unexpected event occurs, i.e. an expected element
102      * is missing in the deserialization process.
103      *
104      * Examples:
105      * ---
106      * auto archive = new XmlArchive!();
107      * auto serializer = new Serializer(archive);
108      * serializer.errorCallback = (SerializationException exception) {
109      *     writeln(exception);
110      *     throw exception;
111      * };
112      * ---
113      */
114     ErrorCallback errorCallback ()
115     {
116         return archive.errorCallback;
117     }
118 
119     /**
120      * This callback will be called when an unexpected event occurs, i.e. an expected element
121      * is missing in the deserialization process.
122      *
123      * Examples:
124      * ---
125      * auto archive = new XmlArchive!();
126      * auto serializer = new Serializer(archive);
127      * serializer.errorCallback = (SerializationException exception) {
128      *     writeln(exception);
129      *     throw exception;
130      * };
131      * ---
132      */
133     ErrorCallback errorCallback (ErrorCallback errorCallback)
134     {
135         return archive.errorCallback = errorCallback;
136     }
137 
138     private
139     {
140         struct ValueMeta
141         {
142             Id id = Id.max;
143             string key;
144 
145             bool isValid ()
146             {
147                 return id != Id.max && key.length > 0;
148             }
149         }
150 
151         static
152         {
153             void function (Serializer serializer, in Object, Mode mode) [ClassInfo] registeredTypes;
154             RegisterBase[string] serializers;
155             RegisterBase[string] deserializers;
156         }
157 
158         Archive archive_;
159 
160         size_t keyCounter;
161         Id idCounter;
162 
163         RegisterBase[string] overriddenSerializers;
164         RegisterBase[string] overriddenDeserializers;
165 
166         Id[void*] serializedReferences;
167         void*[Id] deserializedReferences;
168 
169         Array[Id] serializedArrays;
170         void[][Id] deserializedSlices;
171 
172         void**[Id] deserializedPointers;
173 
174         ValueMeta[void*] serializedValues;
175 
176         const(void)*[Id] deserializedValues;
177 
178         bool hasBegunSerializing;
179         bool hasBegunDeserializing;
180 
181         void delegate (SerializationException exception) throwOnErrorCallback;
182         void delegate (SerializationException exception) doNothingOnErrorCallback;
183 
184         Mode mode;
185     }
186 
187     /**
188      * Creates a new serializer using the given archive.
189      *
190      * The archive is the backend of the (de)serialization process, it performs the low
191      * level (de)serialization of primitive values and it decides the final format of the
192      * serialized data.
193      *
194      * Params:
195      *     archive = the archive that should be used for this serializer
196      *
197      * Examples:
198      * ---
199      * auto archive = new XmlArchive!();
200      * auto serializer = new Serializer(archive);
201      * ---
202      */
203     this (Archive archive)
204     {
205         this.archive_ = archive;
206 
207         throwOnErrorCallback = (SerializationException exception) { throw exception; };
208         doNothingOnErrorCallback = (SerializationException exception) { /* do nothing */ };
209 
210         setThrowOnErrorCallback();
211     }
212 
213     /**
214      * Registers the given type for (de)serialization.
215      *
216      * This method is used for register classes that will be (de)serialized through base
217      * class references, no other types need to be registered. If the the user tries to
218      * (de)serialize an instance through a base class reference which runtime type is not
219      * registered an exception will be thrown.
220      *
221      * Params:
222      *     T = the type to register, must be a class
223      *
224      * Examples:
225      * ---
226      * class Base {}
227      * class Sub : Base {}
228      *
229      * Serializer.register!(Sub);
230      *
231      * auto archive = new XmlArchive!();
232      * auto serializer = new Serializer(archive);
233      *
234      * Base b = new Sub;
235      * serializer.serialize(b);
236      * ---
237      *
238      * See_Also: registerSerializer
239      * See_Also: registerDeserializer
240      */
241     static void register (T : Object) ()
242     {
243         registeredTypes[T.classinfo] = &downcastSerialize!(T);
244     }
245 
246     private static void downcastSerialize (U : Object) (Serializer serializer, in Object value, Mode mode)
247     {
248         alias Unqual!(U) T;
249 
250         static if (!isNonSerialized!(T)())
251         {
252             auto casted = cast(T) value;
253             assert(casted);
254             assert(casted.classinfo is T.classinfo);
255 
256             if (mode == serializing)
257                 serializer.objectStructSerializeHelper(casted);
258 
259             else
260                 serializer.objectStructDeserializeHelper(casted);
261         }
262     }
263 
264     /**
265      * Registers a serializer for the given type.
266      *
267      * The given callback will be called when a value of the given type is about to
268      * be serialized. This method can be used as an alternative to $(I register). This
269      * method can also be used as an alternative to Serializable.toData.
270      *
271      * This is method should also be used to perform custom serialization of third party
272      * types or when otherwise chaining an already existing type is not desired.
273      *
274      * Params:
275      *     dg = the callback that will be called when value of the given type is about to be serialized
276      *
277      * Examples:
278      * ---
279      * class Base {}
280      * class Foo : Base {}
281      *
282      * auto archive = new XmlArchive!();
283      * auto serializer = new Serializer(archive);
284      *
285      * auto dg = (Base value, Serializer serializer, Data key) {
286      *     // perform serialization
287      * };
288      *
289      * Serializer.registerSerializer!(Foo)(dg);
290      * ---
291      *
292      * See_Also: register
293      * See_Also: registerDeserializer
294      * See_Also: Serializable.toData
295      */
296     static void registerSerializer (Derived, Base) (void delegate (Base, Serializer, Data) dg)
297     {
298         Serializer.serializers[typeid(Derived).toString] = toSerializeRegisterWrapper(dg);
299     }
300 
301     /**
302      * Registers a serializer for the given type.
303      *
304      * The given callback will be called when a value of the given type is about to
305      * be serialized. This method can be used as an alternative to $(I register). This
306      * method can also be used as an alternative to Serializable.toData.
307      *
308      * This is method should also be used to perform custom serialization of third party
309      * types or when otherwise chaining an already existing type is not desired.
310      *
311      * Params:
312      *     dg = the callback that will be called when value of the given type is about to be serialized
313      *
314      * Examples:
315      * ---
316      * class Base {}
317      * class Foo : Base {}
318      *
319      * auto archive = new XmlArchive!();
320      * auto serializer = new Serializer(archive);
321      *
322      * void func (Base value, Serializer serializer, Data key) {
323      *     // perform serialization
324      * }
325      *
326      * Serializer.registerSerializer!(Foo)(&func);
327      * ---
328      *
329      * See_Also: register
330      * See_Also: registerDeserializer
331      * See_Also: Serializable.toData
332      */
333     static void registerSerializer (Derived, Base) (void function (Base, Serializer, Data) func)
334     {
335         Serializer.serializers[typeid(Derived).toString] = toSerializeRegisterWrapper(func);
336     }
337 
338     /**
339      * Registers a deserializer for the given type.
340      *
341      * The given callback will be called when a value of the given type is about to
342      * be deserialized. This method can be used as an alternative to $(I register). This
343      * method can also be used as an alternative to Serializable.fromData.
344      *
345      * This is method should also be used to perform custom deserialization of third party
346      * types or when otherwise chaining an already existing type is not desired.
347      *
348      * Params:
349      *     dg = the callback that will be called when value of the given type is about to be deserialized
350      *
351      * Examples:
352      * ---
353      * class Base {}
354      * class Foo : Base {}
355      *
356      * auto archive = new XmlArchive!();
357      * auto serializer = new Serializer(archive);
358      *
359      * auto dg = (ref Base value, Serializer serializer, Data key) {
360      *     // perform deserialization
361      * };
362      *
363      * Serializer.registerDeserializer!(Foo)(dg);
364      * ---
365      *
366      * See_Also: register
367      * See_Also: registerSerializer
368      * See_Also: Serializable.fromData
369      */
370     static void registerDeserializer (Derived, Base) (void delegate (ref Base, Serializer, Data) dg)
371     {
372         Serializer.deserializers[typeid(Derived).toString] = toDeserializeRegisterWrapper(dg);
373     }
374 
375     /**
376      * Registers a deserializer for the given type.
377      *
378      * The given callback will be called when a value of the given type is about to
379      * be deserialized. This method can be used as an alternative to $(I register). This
380      * method can also be used as an alternative to Serializable.fromData.
381      *
382      * This is method should also be used to perform custom deserialization of third party
383      * types or when otherwise chaining an already existing type is not desired.
384      *
385      * Params:
386      *     dg = the callback that will be called when value of the given type is about to be deserialized
387      *
388      * Examples:
389      * ---
390      * class Base {}
391      * class Foo : Base {}
392      *
393      * auto archive = new XmlArchive!();
394      * auto serializer = new Serializer(archive);
395      *
396      * void func (ref Base value, Serializer serializer, Data key) {
397      *     // perform deserialization
398      * }
399      *
400      * Serializer.registerDeserializer!(Foo)(&func);
401      * ---
402      *
403      * See_Also: register
404      * See_Also: registerSerializer
405      * See_Also: Serializable.fromData
406      */
407     static void registerDeserializer (Derived, Base) (void function (ref Base, Serializer, Data) func)
408     {
409         Serializer.deserializers[typeid(Derived).toString] = toDeserializeRegisterWrapper(func);
410     }
411 
412     /**
413      * Overrides a globally registered serializer for the given type with a serializer
414      * local to the receiver.
415      *
416      * The receiver will first check if a local serializer is registered, otherwise a global
417      * serializer will be used (if available).
418      *
419      * Params:
420      *     dg = the callback that will be called when value of the given type is about to be serialized
421      *
422      * Examples:
423      * ---
424      * class Base {}
425      * class Foo : Base {}
426      *
427      * auto archive = new XmlArchive!();
428      * auto serializer = new Serializer(archive);
429      *
430      * auto dg = (Base value, Serializer serializer, Data key) {
431      *     // perform serialization
432      * };
433      *
434      * Serializer.registerSerializer!(Foo)(dg);
435      *
436      * auto overrideDg = (Base value, Serializer serializer, Data key) {
437      *     // this will override the above serializer
438      * }
439      *
440      * serializer.overrideSerializer!(Foo)(overrideDg);
441      * ---
442      */
443     void overrideSerializer (Derived, Base) (void delegate (Base, Serializer, Data) dg)
444     {
445         overriddenSerializers[typeid(Derived).toString] = toSerializeRegisterWrapper(dg);
446     }
447 
448     /**
449      * Overrides a globally registered serializer for the given type with a serializer
450      * local to the receiver.
451      *
452      * The receiver will first check if a local serializer is registered, otherwise a global
453      * serializer will be used (if available).
454      *
455      * Params:
456      *     dg = the callback that will be called when value of the given type is about to be serialized
457      *
458      * Examples:
459      * ---
460      * class Base {}
461      * class Foo : Base {}
462      *
463      * auto archive = new XmlArchive!();
464      * auto serializer = new Serializer(archive);
465      *
466      * void func (Base value, Serializer serializer, Data key) {
467      *     // perform serialization
468      * }
469      *
470      * Serializer.registerSerializer!(Foo)(&func);
471      *
472      * void overrideFunc (Base value, Serializer serializer, Data key) {
473      *     // this will override the above serializer
474      * }
475      *
476      * serializer.overrideSerializer!(Foo)(&overrideFunc);
477      * ---
478      */
479     void overrideSerializer (Derived, Base) (void function (Base, Serializer, Data) func)
480     {
481         overriddenSerializers[typeid(Derived).toString] = toSerializeRegisterWrapper(func);
482     }
483 
484     /**
485      * Overrides a globally registered deserializer for the given type with a deserializer
486      * local to the receiver.
487      *
488      * The receiver will first check if a local deserializer is registered, otherwise a global
489      * deserializer will be used (if available).
490      *
491      * Params:
492      *     dg = the callback that will be called when value of the given type is about to be deserialized
493      *
494      * Examples:
495      * ---
496      * class Base {}
497      * class Foo : Base {}
498      *
499      * auto archive = new XmlArchive!();
500      * auto serializer = new Serializer(archive);
501      *
502      * auto dg = (ref Base value, Serializer serializer, Data key) {
503      *     // perform deserialization
504      * };
505      *
506      * Serializer.registerSerializer!(Foo)(dg);
507      *
508      * auto overrideDg = (ref Base value, Serializer serializer, Data key) {
509      *     // this will override the above deserializer
510      * };
511      *
512      * serializer.overrideSerializer!(Foo)(overrideDg);
513      * ---
514      */
515     void overrideDeserializer (Derived, Base) (void delegate (ref Base, Serializer, Data) dg)
516     {
517         overriddenDeserializers[typeid(Derived).toString] = toDeserializeRegisterWrapper(dg);
518     }
519 
520     /**
521      * Overrides a globally registered deserializer for the given type with a deserializer
522      * local to the receiver.
523      *
524      * The receiver will first check if a local deserializer is registered, otherwise a global
525      * deserializer will be used (if available).
526      *
527      * Params:
528      *     dg = the callback that will be called when value of the given type is about to be deserialized
529      *
530      * Examples:
531      * ---
532      * class Base {}
533      * class Foo : Base {}
534      *
535      * auto archive = new XmlArchive!();
536      * auto serializer = new Serializer(archive);
537      *
538      * void func (ref Base value, Serializer serializer, Data key) {
539      *     // perform deserialization
540      * }
541      *
542      * Serializer.registerSerializer!(Foo)(&func);
543      *
544      * void overrideFunc (ref Base value, Serializer serializer, Data key) {
545      *     // this will override the above deserializer
546      * }
547      *
548      * serializer.overrideSerializer!(Foo)(&overrideFunc);
549      * ---
550      */
551     void overrideDeserializer (Derived, Base) (void function (ref Base, Serializer, Data) func)
552     {
553         overriddenDeserializers[typeid(Derived).toString] = toDeserializeRegisterWrapper(func);
554     }
555 
556     /// Returns the receivers archive
557     Archive archive ()
558     {
559         return archive_;
560     }
561 
562     /**
563      * Set the error callback to throw when an error occurs
564      *
565      * See_Also: setDoNothingOnErrorCallback
566      */
567     void setThrowOnErrorCallback ()
568     {
569         errorCallback = throwOnErrorCallback;
570     }
571 
572     /**
573      * Set the error callback do nothing when an error occurs
574      *
575      * See_Also: setThrowOnErrorCallback
576      */
577     void setDoNothingOnErrorCallback ()
578     {
579         errorCallback = doNothingOnErrorCallback;
580     }
581 
582     /**
583      * Resets all registered types registered via the "register" method
584      *
585      * See_Also: register
586      */
587     static void resetRegisteredTypes ()
588     {
589         registeredTypes = null;
590     }
591 
592     /**
593      * Resets all registered (de)serializers registered via the "registerSerializer" method.
594      * This method will not reset the overridden (de)serializers.
595      *
596      * See_Also: registerSerializer
597      * See_Also: registerDeserializer
598      */
599     static void resetSerializers ()
600     {
601         serializers = null;
602         deserializers = null;
603     }
604 
605     /**
606      * Resets the serializer.
607      *
608      * All internal data is reset, including the archive. After calling this method the
609      * serializer can be used to start a completely new (de)serialization process.
610      */
611     void reset ()
612     {
613         resetCounters();
614 
615         overriddenSerializers = null;
616         overriddenDeserializers = null;
617 
618         serializedReferences = null;
619         deserializedReferences = null;
620 
621         serializedArrays = null;
622         deserializedSlices = null;
623 
624         serializedValues = null;
625         deserializedValues = null;
626 
627         deserializedPointers = null;
628 
629         hasBegunSerializing = false;
630         hasBegunDeserializing = false;
631 
632         archive.reset;
633 
634         mode = Mode.init;
635     }
636 
637     /**
638      * Serializes the given value.
639      *
640      * Params:
641      *     value = the value to serialize
642      *     key = associates the value with the given key. This key can later be used to
643      *              deserialize the value
644      *
645       * Examples:
646      * ---
647      * auto archive = new XmlArchive!();
648      * auto serializer = new Serializer(archive);
649      *
650      * serializer.serialize(1);
651      * serializer.serialize(2, "b");
652      * ---
653      *
654      * Returns: return the serialized data, in an untyped format.
655      *
656      * Throws: SerializationException if an error occurs
657      */
658     Data serialize (T) (T value, string key = null)
659     {
660         mode = serializing;
661 
662         if (!hasBegunSerializing)
663             hasBegunSerializing = true;
664 
665         serializeInternal(value, key);
666         postProcess;
667 
668         return archive.untypedData;
669     }
670 
671     /**
672      * Serializes the base class(es) of an instance.
673      *
674      * This method is used when performing custom serialization of a given type. If this
675      * method is not called when performing custom serialization none of the instance's
676      * base classes will be serialized.
677      *
678      * Params:
679      *     value = the instance which base class(es) should be serialized, usually $(D_CODE this)
680      *
681      * Examples:
682      * ---
683      * class Base {}
684      * class Sub : Base
685      * {
686      *     void toData (Serializer serializer, Serializer.Data key)
687      *     {
688      *         // perform serialization
689      *         serializer.serializeBase(this);
690      *     }
691      * }
692      * ---
693      *
694      * Throws: SerializationException if an error occurs
695      */
696     void serializeBase (T) (T value)
697     {
698         static if (isObject!(T) && !is(Unqual!(T) == Object))
699                 serializeBaseTypes(value);
700     }
701 
702     private void serializeInternal (U) (ref U value, string key = null, Id id = Id.max)
703     {
704         alias Unqual!(U) T;
705 
706         if (!key)
707             key = nextKey;
708 
709         if (id == Id.max)
710             id = nextId;
711 
712         archive.beginArchiving();
713 
714         static if (isObject!(T))
715             serializeObject(value, key, id);
716 
717         else static if (isStruct!(T))
718             serializeStruct(value, key, id);
719 
720         else static if (isString!(T))
721             serializeString(value, key, id);
722 
723         else static if (isArray!(T))
724             serializeArray(value, key, id);
725 
726         else static if (isAssociativeArray!(T))
727             serializeAssociativeArray(value, key, id);
728 
729         else static if (isPrimitive!(T))
730             serializePrimitive(value, key, id);
731 
732         else static if (isPointer!(T))
733         {
734             static if (isFunctionPointer!(T))
735                 goto error;
736 
737             else
738                 serializePointer(value, key, id);
739         }
740 
741         else static if (isEnum!(T))
742             serializeEnum(value, key, id);
743 
744         else
745         {
746             error:
747             error(format!(`The type "`, T, `" cannot be serialized.`));
748         }
749     }
750 
751     private void serializeObject (T) (T value, string key, Id id) if (isObject!(T))
752     {
753         auto typeName = typeid(T).toString;
754 
755         static if (!isNonSerialized!(T)())
756         {
757             if (!value)
758                 return archive.archiveNull(typeName, key);
759 
760             auto reference = getSerializedReference(value);
761 
762             if (reference != Id.max)
763                 return archive.archiveReference(key, reference);
764 
765             auto untypedValue = cast(Object) value;
766             auto runtimeType = untypedValue.classinfo.name;
767 
768             addSerializedReference(value, id);
769 
770             triggerEvents(value, {
771                 archive.archiveObject(runtimeType, typeName, key, id, {
772                     if (auto serializer = runtimeType in overriddenSerializers)
773                         callSerializer(serializer, value, key);
774 
775                     else if (auto serializer = runtimeType in Serializer.serializers)
776                         callSerializer(serializer, value, key);
777 
778                     else static if (isSerializable!(T))
779                         value.toData(this, key);
780 
781                     else
782                     {
783                         if (isInterface!(T) || isBaseClass(value))
784                         {
785                             if (auto serializer = untypedValue.classinfo in registeredTypes)
786                                 (*serializer)(this, untypedValue, serializing);
787 
788                             else
789                                 error(`The object of the static type "` ~ typeName ~
790                                     `" have a different runtime type (` ~ runtimeType ~
791                                     `) and therefore needs to either register its type or register a serializer for its type "`
792                                     ~ runtimeType ~ `".`);
793                         }
794 
795                         else
796                             objectStructSerializeHelper(value);
797                     }
798                 });
799             });
800         }
801     }
802 
803     private void serializeStruct (T) (T value, string key, Id id)
804     {
805         static if (!isNonSerialized!(T)())
806         {
807             string type = typeid(T).toString;
808 
809             triggerEvents(value, {
810                 archive.archiveStruct(type, key, id, {
811                     if (auto serializer = type in overriddenSerializers)
812                         callSerializer(serializer, value, key);
813 
814                     else if (auto serializer = type in Serializer.serializers)
815                         callSerializer(serializer, value, key);
816 
817                     else
818                     {
819                         static if (isSerializable!(T))
820                             value.toData(this, key);
821 
822                         else
823                             objectStructSerializeHelper(value);
824                     }
825                 });
826             });
827         }
828     }
829 
830     private void serializeString (T) (T value, string key, Id id)
831     {
832         auto array = Array(cast(void*) value.ptr, value.length, ElementTypeOfArray!(T).sizeof);
833 
834         archive.archive(value, key, id);
835 
836         if (value.length > 0)
837             addSerializedArray(array, id);
838     }
839 
840     private void serializeArray (T) (ref T value, string key, Id id)
841     {
842         auto array = Array(value.ptr, value.length, ElementTypeOfArray!(T).sizeof);
843 
844         archive.archiveArray(array, arrayToString!(T), key, id, {
845             for (size_t i = 0; i < value.length; i++)
846             {
847                 const e = value[i];
848                 serializeInternal(e, toData(i));
849             }
850         });
851 
852         if (value.length > 0)
853             addSerializedArray(array, id);
854     }
855 
856     private void serializeAssociativeArray (T) (T value, string key, Id id)
857     {
858         auto reference = getSerializedReference(value);
859 
860         if (reference != Id.max)
861             return archive.archiveReference(key, reference);
862 
863         addSerializedReference(value, id);
864 
865         string keyType = typeid(KeyTypeOfAssociativeArray!(T)).toString;
866         string valueType = typeid(ValueTypeOfAssociativeArray!(T)).toString;
867 
868         archive.archiveAssociativeArray(keyType, valueType, value.length, key, id, {
869             size_t i;
870 
871             foreach(k, v ; value)
872             {
873                 archive.archiveAssociativeArrayKey(toData(i), {
874                     serializeInternal(k, toData(i));
875                 });
876 
877                 archive.archiveAssociativeArrayValue(toData(i), {
878                     serializeInternal(v, toData(i));
879                 });
880 
881                 i++;
882             }
883         });
884     }
885 
886     private void serializePointer (T) (T value, string key, Id id)
887     {
888         if (!value)
889             return archive.archiveNull(typeid(T).toString, key);
890 
891         auto reference = getSerializedReference(value);
892 
893         if (reference != Id.max)
894             return archive.archiveReference(key, reference);
895 
896         archive.archivePointer(key, id, {
897             if (auto serializer = key in overriddenSerializers)
898                 callSerializer(serializer, value, key);
899 
900             else if (auto serializer = key in Serializer.serializers)
901                 callSerializer(serializer, value, key);
902 
903             else static if (isSerializable!(T))
904                 value.toData(this, key);
905 
906             else
907             {
908                 static if (isVoid!(BaseTypeOfPointer!(T)))
909                     error(`The value with the key "` ~ to!(string)(key) ~ `"` ~
910                         format!(` of the type "`, T, `" cannot be serialized on `,
911                         `its own, either implement orange.serialization.Serializable`,
912                         `.isSerializable or register a serializer.`));
913 
914                 else
915                 {
916                     auto valueMeta = getSerializedValue(value);
917 
918                     if (valueMeta.isValid)
919                         archive.archiveReference(nextKey, valueMeta.id);
920 
921                     else
922                         serializeInternal(*value, nextKey);
923                 }
924             }
925         });
926 
927         addSerializedReference(value, id);
928     }
929 
930     private void serializeEnum (T) (T value, string key, Id id)
931     {
932         alias BaseTypeOfEnum!(T) EnumBaseType;
933         auto val = cast(EnumBaseType) value;
934         string type = typeid(T).toString;
935 
936         archive.archiveEnum(val, type, key, id);
937     }
938 
939     private void serializePrimitive (T) (T value, string key, Id id)
940     {
941         archive.archive(value, key, id);
942     }
943 
944     /**
945      * Deserializes the given data to value of the given type.
946      *
947      * This is the main method used for deserializing data.
948      *
949      * Examples:
950      * ---
951      * auto archive = new XmlArchive!();
952      * auto serializer = new Serializer(archive);
953      *
954      * auto data = serializer.serialize(1);
955      * auto i = serializer.deserialize!(int)(data);
956      *
957      * assert(i == 1);
958      * ---
959      *
960      * Params:
961      *        T = the type to deserialize the data into
962      *     data = the serialized untyped data to deserialize
963      *     key = the key associate with the value that was used during serialization.
964      *              Do not specify a key if no key was used during serialization.
965      *
966      * Returns: the deserialized value. A different runtime type can be returned
967      *             if the given type is a base class.
968      *
969      * Throws: SerializationException if an error occurs
970      */
971     T deserialize (T) (Data data, string key = "")
972     {
973         mode = deserializing;
974 
975         if (hasBegunSerializing && !hasBegunDeserializing)
976             resetCounters();
977 
978         if (!hasBegunDeserializing)
979             hasBegunDeserializing = true;
980 
981         if (key.empty())
982             key = nextKey;
983 
984         archive.beginUnarchiving(data);
985         auto value = deserializeInternal!(T)(key);
986         deserializingPostProcess;
987 
988         return value;
989     }
990 
991     /**
992      * Deserializes the value with the given associated key.
993      *
994      * This method should only be called when performing custom an deserializing a value
995      * that is part of an class or struct. If this method is called before that actual
996      * deserialization process has begun an SerializationException will be thrown.
997      * Use this method if a key was specified during the serialization process.
998      *
999      * Examples:
1000      * ---
1001      * class Foo
1002      * {
1003      *     int a;
1004      *
1005      *     void fromData (Serializer serializer, Serializer.Data key)
1006      *     {
1007      *         a = serializer!(int)("a");
1008      *     }
1009      * }
1010      * ---
1011      *
1012      * Params:
1013      *     key = the key associate with the value that was used during serialization.
1014      *
1015      * Returns: the deserialized value. A different runtime type can be returned
1016      *             if the given type is a base class.
1017      *
1018      * Throws: SerializationException if this method is called before
1019      *            the actual deserialization process has begun.
1020      *
1021      * Throws: SerializationException if an error occurs
1022      */
1023     T deserialize (T) (string key)
1024     {
1025         if (!hasBegunDeserializing)
1026             error("Cannot deserialize without any data, this method should" ~
1027                 "only be called after deserialization has begun.");
1028 
1029         return deserialize!(T)(archive.untypedData, key);
1030     }
1031 
1032     /**
1033      * Deserializes the value with the given associated key.
1034      *
1035      * This method should only be called when performing custom an deserializing a value
1036      * that is part of an class or struct. If this method is called before that actual
1037      * deserialization process has begun an SerializationException will be thrown.
1038      * Use this method if no key was specified during the serialization process.
1039      *
1040      * Examples:
1041      * ---
1042      * class Foo
1043      * {
1044      *     int a;
1045      *
1046      *     void fromData (Serializer serializer, Serializer.Data key)
1047      *     {
1048      *         a = serializer!(int)();
1049      *     }
1050      * }
1051      * ---
1052      *
1053      * Params:
1054      *     key = the key associate with the value that was used during serialization.
1055      *
1056      * Returns: the deserialized value. A different runtime type can be returned
1057      *             if the given type is a base class.
1058      *
1059      * Throws: SerializationException if this method is called before
1060      *            the actual deserialization process has begun.
1061      *
1062      * Throws: SerializationException if an error occurs
1063      */
1064     T deserialize (T) ()
1065     {
1066         return deserialize!(T)("");
1067     }
1068 
1069     /**
1070      * Deserializes the base class(es) of an instance.
1071      *
1072      * This method is used when performing custom deserialization of a given type. If this
1073      * method is not called when performing custom deserialization none of the instance's
1074      * base classes will be serialized.
1075      *
1076      * Params:
1077      *     value = the instance which base class(es) should be deserialized,
1078      *                usually $(D_CODE this)
1079      *
1080      * Examples:
1081      * ---
1082      * class Base {}
1083      * class Sub : Base
1084      * {
1085      *     void fromData (Serializer serializer, Serializer.Data key)
1086      *     {
1087      *         // perform deserialization
1088      *         serializer.deserializeBase(this);
1089      *     }
1090      * }
1091      * ---
1092      *
1093      * Throws: SerializationException if an error occurs
1094      */
1095     void deserializeBase (T) (T value)
1096     {
1097         static if (isObject!(T) && !is(Unqual!(T) == Object))
1098             deserializeBaseTypes(value);
1099     }
1100 
1101     private Unqual!(U) deserializeInternal (U, Key) (Key keyOrId)
1102     {
1103         Id dummy;
1104         return deserializeInternal!(U, Key)(keyOrId, dummy);
1105     }
1106 
1107     private Unqual!(U) deserializeInternal (U, Key) (Key keyOrId, out Id id)
1108     {
1109         alias Unqual!(U) T;
1110 
1111         static if (isObject!(T))
1112             return deserializeObject!(T)(keyOrId, id);
1113 
1114         else static if (isStruct!(T))
1115             return deserializeStruct!(T)(keyOrId, id);
1116 
1117         else static if (isString!(T))
1118             return deserializeString!(T)(keyOrId, id);
1119 
1120         else static if (isStaticArray!(T))
1121             return deserializeStaticArray!(T)(keyOrId, id);
1122 
1123         else static if (isArray!(T))
1124             return deserializeArray!(T)(keyOrId, id);
1125 
1126         else static if (isAssociativeArray!(T))
1127             return deserializeAssociativeArray!(T)(keyOrId, id);
1128 
1129         else static if (isPrimitive!(T))
1130             return deserializePrimitive!(T)(keyOrId, id);
1131 
1132         else static if (isPointer!(T))
1133         {
1134             static if (isFunctionPointer!(T))
1135                 goto error;
1136 
1137             return deserializePointer!(T)(keyOrId, id).value;
1138         }
1139 
1140         else static if (isEnum!(T))
1141             return deserializeEnum!(T)(keyOrId, id);
1142 
1143         else
1144         {
1145             error:
1146             error(format!(`The type "`, T, `" cannot be deserialized.`));
1147         }
1148     }
1149 
1150     private Unqual!(U) deserializeObject (U, Key) (Key keyOrId, out Id id)
1151     {
1152         alias Unqual!(U) T;
1153 
1154         static if (!isNonSerialized!(T)())
1155         {
1156             id = deserializeReference(keyOrId);
1157 
1158             if (auto reference = getDeserializedReference!(T)(id))
1159                 return *reference;
1160 
1161             T value;
1162             Object untypedValue;
1163             nextId;
1164 
1165             archive.unarchiveObject(keyOrId, id, untypedValue, {
1166                 value = cast(T) untypedValue;
1167                 addDeserializedReference(value, id);
1168                 assert(untypedValue !is null, format!("Failed to unarchive object of type '", T, "' with key '") ~ to!(string)(keyOrId) ~ "'");
1169 
1170                 triggerEvents(value, {
1171                     auto runtimeType = untypedValue.classinfo.name;
1172                     auto runHelper = false;
1173 
1174                     static if (isString!(Key))
1175                     {
1176                         if (auto deserializer = runtimeType in overriddenDeserializers)
1177                             callSerializer(deserializer, value, keyOrId);
1178 
1179                         else if (auto deserializer = runtimeType in Serializer.deserializers)
1180                             callSerializer(deserializer, value, keyOrId);
1181 
1182                         else static if (isSerializable!(T))
1183                             value.fromData(this, keyOrId);
1184 
1185                         else
1186                             runHelper = true;
1187                     }
1188 
1189                     else
1190                         runHelper = true;
1191 
1192                     if (runHelper)
1193                     {
1194                         if (isInterface!(T) || isBaseClass(value))
1195                         {
1196                             if (auto deserializer = untypedValue.classinfo in registeredTypes)
1197                                 (*deserializer)(this, untypedValue, deserializing);
1198 
1199                             else
1200                                 error(`The object of the static type "` ~ typeid(T).toString ~
1201                                     `" have a different runtime type (` ~ runtimeType ~
1202                                     `) and therefore needs to either register its type or register a deserializer for its type "`
1203                                     ~ runtimeType ~ `".`);
1204                         }
1205 
1206                         else
1207                             objectStructDeserializeHelper(value);
1208                     }
1209                 });
1210             });
1211 
1212             return value;
1213         }
1214         else
1215         {
1216             return T.init;
1217         }
1218     }
1219 
1220     private T deserializeStruct (T, U) (U key, out Id id)
1221     {
1222         T value;
1223 
1224         static if (!isNonSerialized!(T)())
1225         {
1226             nextId;
1227 
1228             id = archive.unarchiveStruct(key, {
1229                 triggerEvents(value, {
1230                     auto type = toData(typeid(T).toString);
1231                     auto runHelper = false;
1232 
1233                     static if (isString!(U))
1234                     {
1235                         if (auto deserializer = type in overriddenDeserializers)
1236                             callSerializer(deserializer, value, key);
1237 
1238                         else if (auto deserializer = type in Serializer.deserializers)
1239                             callSerializer(deserializer, value, key);
1240 
1241                         else
1242                             runHelper = true;
1243                     }
1244 
1245                     else
1246                         runHelper = true;
1247 
1248                     if (runHelper)
1249                     {
1250                         static if (isSerializable!(T))
1251                             value.fromData(this, key);
1252 
1253                         else
1254                             objectStructDeserializeHelper(value);
1255                     }
1256                 });
1257             });
1258         }
1259 
1260         return value;
1261     }
1262 
1263     private T deserializeString (T) (string key, out Id id)
1264     {
1265         auto slice = deserializeSlice(key);
1266 
1267         if (auto tmp = getDeserializedSlice!(T)(slice))
1268             return tmp;
1269 
1270         T value;
1271 
1272         if (slice.id != size_t.max)
1273         {
1274             static if (is(T == string))
1275                 value = toSlice(archive.unarchiveString(slice.id), slice);
1276 
1277             else static if (is(T == wstring))
1278                 value = toSlice(archive.unarchiveWstring(slice.id), slice);
1279 
1280             else static if (is(T == dstring))
1281                 value = toSlice(archive.unarchiveDstring(slice.id), slice);
1282         }
1283 
1284         else
1285         {
1286             static if (is(T == string))
1287                 value = archive.unarchiveString(key, slice.id);
1288 
1289             else static if (is(T == wstring))
1290                 value = archive.unarchiveWstring(key, slice.id);
1291 
1292             else static if (is(T == dstring))
1293                 value = archive.unarchiveDstring(key, slice.id);
1294         }
1295 
1296         addDeserializedSlice(value, slice.id);
1297 
1298         id = slice.id;
1299         return value;
1300     }
1301 
1302     private T deserializeArray (T) (string key, out Id id)
1303     {
1304         auto slice = deserializeSlice(key);
1305 
1306         if (auto tmp = getDeserializedSlice!(T)(slice))
1307             return tmp;
1308 
1309         alias ElementTypeOfArray!(T) E;
1310         alias Unqual!(E) UnqualfiedE;
1311 
1312         UnqualfiedE[] buffer;
1313         T value;
1314 
1315         auto dg = (size_t length) {
1316             buffer.length = length;
1317 
1318             foreach (i, ref e ; buffer)
1319                 e = deserializeInternal!(typeof(e))(toData(i));
1320         };
1321 
1322         if (slice.id != size_t.max) // Deserialize slice
1323         {
1324             id = slice.id;
1325             archive.unarchiveArray(slice.id, dg);
1326             assumeUnique(buffer, value);
1327             addDeserializedSlice(value, slice.id);
1328 
1329             return toSlice(value, slice);
1330         }
1331 
1332         else // Deserialize array
1333         {
1334             id = archive.unarchiveArray(key, dg);
1335 
1336             if (auto arr = id in deserializedSlices)
1337                 return cast(T) *arr;
1338 
1339             assumeUnique(buffer, value);
1340             addDeserializedSlice(value, id);
1341 
1342             return value;
1343         }
1344     }
1345 
1346     private T deserializeStaticArray (T) (string key, out Id id)
1347     {
1348         T value;
1349 
1350         id = archive.unarchiveArray(key, (size_t length) {
1351             foreach (i, ref e ; value)
1352                 e = deserializeInternal!(typeof(e))(toData(i));
1353         });
1354 
1355         return value;
1356     }
1357 
1358     private T deserializeAssociativeArray (T) (string key, out Id id)
1359     {
1360         id = deserializeReference(key);
1361 
1362         if (auto reference = getDeserializedReference!(T)(id))
1363             return *reference;
1364 
1365         alias KeyTypeOfAssociativeArray!(T) Key;
1366         alias ValueTypeOfAssociativeArray!(T) Value;
1367 
1368         alias Unqual!(Key) UKey;
1369         alias Unqual!(Value) UValue;
1370 
1371         UValue[UKey] buffer;
1372 
1373         id = archive.unarchiveAssociativeArray(key, (size_t length) {
1374             for (size_t i = 0; i < length; i++)
1375             {
1376                 UKey aaKey;
1377                 UValue aaValue;
1378                 auto k = toData(i);
1379 
1380                 archive.unarchiveAssociativeArrayKey(k, {
1381                     aaKey = deserializeInternal!(Key)(k);
1382                 });
1383 
1384                 archive.unarchiveAssociativeArrayValue(k, {
1385                     aaValue = deserializeInternal!(Value)(k);
1386                 });
1387 
1388                 buffer[aaKey] = aaValue;
1389             }
1390         });
1391 
1392         T value = buffer;
1393         addDeserializedReference(value, id);
1394 
1395         return value;
1396     }
1397 
1398     private Pointer!(T) deserializePointer (T) (string key)
1399     {
1400         auto pointeeId = deserializeReference(key);
1401 
1402         if (auto reference = getDeserializedReference!(T)(pointeeId))
1403             return Pointer!(T)(*reference, Id.max);
1404 
1405         alias BaseTypeOfPointer!(T) BaseType;
1406         alias Unqual!(BaseType) UnqualfiedBaseType;
1407 
1408         auto pointer = new UnqualfiedBaseType;
1409 
1410         auto pointerId = archive.unarchivePointer(key, {
1411             if (auto deserializer = key in overriddenDeserializers)
1412                 callSerializer(deserializer, pointer, key);
1413 
1414             else if (auto deserializer = key in Serializer.deserializers)
1415                 callSerializer(deserializer, pointer, key);
1416 
1417             else static if (isSerializable!(T))
1418                 pointer.fromData(this, key);
1419 
1420             else
1421             {
1422                 static if (isVoid!(BaseTypeOfPointer!(T)))
1423                     error(`The value with the key "` ~ to!(string)(key) ~ `"` ~
1424                         format!(` of the type "`, T, `" cannot be ` ~
1425                         "deserialized on its own, either implement " ~
1426                         "orange.serialization.Serializable.isSerializable or " ~
1427                         "register a deserializer."));
1428 
1429                 else
1430                 {
1431                     auto k = nextKey;
1432                     pointeeId = deserializeReference(k);
1433 
1434                     if (pointeeId == Id.max)
1435                         *pointer = deserializeInternal!(UnqualfiedBaseType)(k);
1436                 }
1437             }
1438         });
1439 
1440         if (pointeeId != Id.max)
1441             *pointer = deserializeInternal!(UnqualfiedBaseType)(pointeeId);
1442 
1443         addDeserializedReference(pointer, pointerId);
1444 
1445         return Pointer!(T)(cast(T) pointer, pointerId, pointeeId);
1446     }
1447 
1448     private T deserializeEnum (T, U) (U keyOrId, out Id id)
1449     {
1450         alias BaseTypeOfEnum!(T) Enum;
1451 
1452         enum functionName = toUpper(Enum.stringof[0]) ~ Enum.stringof[1 .. $];
1453 
1454         static if (is(U == Id))
1455             enum params = "(keyOrId);";
1456         else
1457             enum params = "(keyOrId, id);";
1458 
1459         mixin("return cast(T) archive.unarchiveEnum" ~ functionName ~ params);
1460     }
1461 
1462     private T deserializePrimitive (T, U) (U keyOrId, out Id id)
1463     {
1464         enum functionName = toUpper(T.stringof[0]) ~ T.stringof[1 .. $];
1465 
1466         static if (is(U == Id))
1467             enum params = "(keyOrId);";
1468         else
1469             enum params = "(keyOrId, id);";
1470 
1471         mixin("return archive.unarchive" ~ functionName ~ params);
1472     }
1473 
1474     private Id deserializeReference (string key)
1475     {
1476         return archive.unarchiveReference(key);
1477     }
1478 
1479     private Slice deserializeSlice (string key)
1480     {
1481         return archive.unarchiveSlice(key);
1482     }
1483 
1484     private void objectStructSerializeHelper (T) (ref T value)
1485     {
1486         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.`));
1487 
1488         enum nonSerializedFields = collectAnnotations!(T);
1489 
1490         foreach (i, _ ; typeof(T.tupleof))
1491         {
1492             enum field = nameOfFieldAt!(T, i);
1493             alias attributes = getAttributes!(T.tupleof[i]);
1494 
1495             static if (attributes.contains!(nonSerialized) ||
1496                 ctfeContains!(string)(internalFields, field) ||
1497                 ctfeContains!(string)(nonSerializedFields, field))
1498             {
1499                 continue;
1500             }
1501 
1502             alias typeof(T.tupleof[i]) Type;
1503 
1504             auto id = nextId;
1505 
1506             static if (isPointer!(Type))
1507                 auto pointer = value.tupleof[i];
1508 
1509             else
1510                 auto pointer = &value.tupleof[i];
1511 
1512             auto reference = getSerializedReference(value.tupleof[i]);
1513 
1514             if (reference != Id.max)
1515                 archive.archiveReference(field, reference);
1516 
1517             else
1518             {
1519                 auto valueMeta = getSerializedValue(pointer);
1520 
1521                 if (valueMeta.isValid)
1522                     serializePointer(pointer, toData(field), id);
1523 
1524                 else
1525                 {
1526                     serializeInternal(value.tupleof[i], toData(field), id);
1527                     addSerializedValue(pointer, id, toData(keyCounter));
1528                 }
1529             }
1530         }
1531 
1532         static if (isObject!(T) && !is(Unqual!(T) == Object))
1533             serializeBaseTypes(value);
1534     }
1535 
1536     private void objectStructDeserializeHelper (T) (ref T value)
1537     {
1538         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.`));
1539 
1540         enum nonSerializedFields = collectAnnotations!(T);
1541 
1542         static if (isObject!(T))
1543             auto rawObject = cast(void*) value;
1544 
1545         else
1546             auto rawObject = cast(void*) &value;
1547 
1548         foreach (i, _ ; typeof(T.tupleof))
1549         {
1550             enum field = nameOfFieldAt!(T, i);
1551             alias attributes = getAttributes!(T.tupleof[i]);
1552 
1553             static if (attributes.contains!(nonSerialized) ||
1554                 ctfeContains!(string)(internalFields, field) ||
1555                 ctfeContains!(string)(nonSerializedFields, field))
1556             {
1557                 continue;
1558             }
1559 
1560             alias TypeOfField!(T, field) QualifiedType;
1561             alias Unqual!(QualifiedType) Type;
1562 
1563             auto id = deserializeReference(field);
1564             auto isReference = id != Id.max;
1565             auto offset = value.tupleof[i].offsetof;
1566             auto fieldAddress = cast(Type*) (rawObject + offset);
1567 
1568             static if (isPointer!(Type))
1569             {
1570                 auto pointer = deserializePointer!(Type)(toData(field));
1571                 Type pointerValue;
1572 
1573                 if (pointer.hasPointee)
1574                     pointerValue = getDeserializedValue!(Type)(pointer.pointee);
1575 
1576                 else
1577                     pointerValue = pointer.value;
1578 
1579                 *fieldAddress = pointerValue;
1580                 addDeserializedPointer(value.tupleof[i], pointer.id);
1581             }
1582 
1583             else
1584             {
1585                 auto pointer = getDeserializedPointer!(Type*)(id);
1586 
1587                 if (isReference && pointer)
1588                 {
1589                     *fieldAddress = **pointer;
1590                     *pointer = cast(Type*) &value.tupleof[i];
1591                 }
1592 
1593                 else
1594                 {
1595                     *fieldAddress = deserializeInternal!(Type)(toData(field), id);
1596                     addDeserializedValue(value.tupleof[i], id);
1597 
1598                     static if (isStaticArray!(Type))
1599                         addDeserializedSlice(value.tupleof[i], id);
1600                 }
1601             }
1602         }
1603 
1604         static if (isObject!(T) && !is(Unqual!(T) == Object))
1605             deserializeBaseTypes(value);
1606     }
1607 
1608     private void serializeBaseTypes (T) (inout T value) if (isObject!(T))
1609     {
1610         static if (hasNonObjectBaseType!(T))
1611         {
1612             alias Base = BaseTypeTupleOf!(T)[0];
1613             archive.archiveBaseClass(typeid(Base).toString, nextKey, nextId);
1614             inout Base base = value;
1615             objectStructSerializeHelper(base);
1616         }
1617     }
1618 
1619     private void deserializeBaseTypes (T) (T value) if (isObject!(T))
1620     {
1621         static if (hasNonObjectBaseType!(T))
1622         {
1623             alias Base = BaseTypeTupleOf!(T)[0];
1624             archive.unarchiveBaseClass(nextKey);
1625             Base base = value;
1626             objectStructDeserializeHelper(base);
1627         }
1628     }
1629 
1630     private void addSerializedReference (T) (T value, Id id)
1631     {
1632         alias Unqual!(T) Type;
1633         static assert(isReference!(Type) || isAssociativeArray!(Type), format!(`The given type "`, T, `" is not a reference type, i.e. object, pointer or associative array.`));
1634 
1635         serializedReferences[cast(void*) value] = id;
1636     }
1637 
1638     private void addDeserializedReference (T) (T value, Id id)
1639     {
1640         static assert(isReference!(T) || isAssociativeArray!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object, pointer or associative array.`));
1641 
1642         deserializedReferences[id] = cast(void*) value;
1643     }
1644 
1645     private void addDeserializedSlice (T) (ref T value, Id id)
1646     {
1647         static assert(isArray!(T) || isString!(T), format!(`The given type "`, T, `" is not a slice type, i.e. array or string.`));
1648 
1649         deserializedSlices[id] = cast(void[]) value;
1650     }
1651 
1652     private void addSerializedValue (T) (T* value, Id id, string key)
1653     {
1654         serializedValues[value] = ValueMeta(id, key);
1655     }
1656 
1657     private void addDeserializedValue (T) (ref T value, Id id)
1658     {
1659         deserializedValues[id] = &value;
1660     }
1661 
1662     private void addDeserializedPointer (T) (ref T value, Id id)
1663     {
1664         deserializedPointers[id] = cast(void**) &value;
1665     }
1666 
1667     private Id getSerializedReference (T) (T value)
1668     {
1669         if (auto tmp = *(cast(void**) &value) in serializedReferences)
1670             return *tmp;
1671 
1672         return Id.max;
1673     }
1674 
1675     private ValueMeta getSerializedValue (T) (T* value)
1676     {
1677         if (auto tmp = value in serializedValues)
1678             return *tmp;
1679 
1680         return ValueMeta();
1681     }
1682 
1683     private T* getDeserializedReference (T) (Id id)
1684     {
1685         if (auto reference = id in deserializedReferences)
1686             return cast(T*) reference;
1687 
1688         return null;
1689     }
1690 
1691     private T getDeserializedSlice (T) (Slice slice)
1692     {
1693         if (auto array = slice.id in deserializedSlices)
1694         {
1695             auto typed = cast(T) *array;
1696             return typed[slice.offset .. slice.offset + slice.length];
1697         }
1698 
1699         return null;
1700     }
1701 
1702     private T getDeserializedValue (T) (Id id)
1703     {
1704         if (auto value = id in deserializedValues)
1705             return cast(T) *value;
1706 
1707         return null;
1708     }
1709 
1710     private T* getDeserializedPointer (T) (Id id)
1711     {
1712         if (auto pointer = id in deserializedPointers)
1713             return cast(T*) *pointer;
1714 
1715         return null;
1716     }
1717 
1718     private T[] toSlice (T) (T[] array, Slice slice)
1719     {
1720         return array[slice.offset .. slice.offset + slice.length];
1721     }
1722 
1723     void callSerializer (T) (RegisterBase* baseWrapper, ref T value, string key)
1724     {
1725         if (mode == serializing)
1726         {
1727             auto wrapper = cast(SerializeRegisterWrapper!(T)) *baseWrapper;
1728             wrapper(value, this, key);
1729         }
1730 
1731         else
1732         {
1733             auto wrapper = cast(DeserializeRegisterWrapper!(T)) *baseWrapper;
1734             wrapper(value, this, key);
1735         }
1736     }
1737 
1738     static private SerializeRegisterWrapper!(T) toSerializeRegisterWrapper (T) (void delegate (T, Serializer, Data) dg)
1739     {
1740         return new SerializeRegisterWrapper!(T)(dg);
1741     }
1742 
1743     static private SerializeRegisterWrapper!(T) toSerializeRegisterWrapper (T) (void function (T, Serializer, Data) func)
1744     {
1745         return new SerializeRegisterWrapper!(T)(func);
1746     }
1747 
1748     static private DeserializeRegisterWrapper!(T) toDeserializeRegisterWrapper (T) (void delegate (ref T, Serializer, Data) dg)
1749     {
1750         return new DeserializeRegisterWrapper!(T)(dg);
1751     }
1752 
1753     static private DeserializeRegisterWrapper!(T) toDeserializeRegisterWrapper (T) (void function (ref T, Serializer, Data) func)
1754     {
1755         return new DeserializeRegisterWrapper!(T)(func);
1756     }
1757 
1758     private void addSerializedArray (Array array, Id id)
1759     {
1760         serializedArrays[id] = array;
1761     }
1762 
1763     private void postProcess ()
1764     {
1765         postProcessArrays();
1766     }
1767 
1768     private void postProcessArrays ()
1769     {
1770         bool foundSlice = true;
1771 
1772         foreach (sliceKey, slice ; serializedArrays)
1773         {
1774             foreach (arrayKey, array ; serializedArrays)
1775             {
1776                 if (slice.isSliceOf(array) && slice != array)
1777                 {
1778                     auto s = Slice(slice.length, (slice.ptr - array.ptr) / slice.elementSize);
1779                     archive.archiveSlice(s, sliceKey, arrayKey);
1780                     foundSlice = true;
1781                     break;
1782                 }
1783 
1784                 else
1785                     foundSlice = false;
1786             }
1787 
1788             if (!foundSlice)
1789                 archive.postProcessArray(sliceKey);
1790         }
1791     }
1792 
1793     private void deserializingPostProcess ()
1794     {
1795         deserializingPostProcessPointers;
1796     }
1797 
1798     private void deserializingPostProcessPointers ()
1799     {
1800         // foreach (pointeeId, pointee ; deserializedValues)
1801         // {
1802         //     if (auto pointer = pointeeId in deserializedPointers)
1803         //         **pointer = pointee;
1804         // }
1805     }
1806 
1807     private string arrayToString (T) ()
1808     {
1809         return typeid(ElementTypeOfArray!(T)).toString;
1810     }
1811 
1812     private bool isBaseClass (T) (T value)
1813     {
1814         return value.classinfo !is T.classinfo;
1815     }
1816 
1817     private Id nextId ()
1818     {
1819         return idCounter++;
1820     }
1821 
1822     private string nextKey ()
1823     {
1824         return toData(keyCounter++);
1825     }
1826 
1827     private void resetCounters ()
1828     {
1829         keyCounter = 0;
1830         idCounter = 0;
1831     }
1832 
1833     private string toData (T) (T value)
1834     {
1835         return to!(string)(value);
1836     }
1837 
1838     private void triggerEvent (string name, T) (T value)
1839     {
1840         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.`));
1841 
1842         static if (hasAnnotation!(T, name))
1843         {
1844             mixin("auto event = T." ~ name ~ ";");
1845             event(value);
1846         }
1847     }
1848 
1849     private void triggertUdaEvent (alias event, T) (T value)
1850     {
1851         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.`));
1852 
1853         foreach (m ; __traits(allMembers, T))
1854         {
1855             static if (m != nonSerializedField)
1856             {
1857                 mixin(`alias attrs = Attributes!(m, __traits(getAttributes, T.` ~ m ~ `));`);
1858 
1859                 static if (attrs.contains!(event))
1860                     __traits(getMember, value, m)();
1861             }
1862         }
1863     }
1864 
1865     private void triggerEvents (T) (T value, void delegate () dg)
1866     {
1867         if (mode == serializing)
1868         {
1869             triggerEvent!(onSerializingField)(value);
1870             triggertUdaEvent!(onSerializing)(value);
1871         }
1872 
1873         else
1874         {
1875             triggerEvent!(onDeserializingField)(value);
1876             triggertUdaEvent!(onDeserializing)(value);
1877         }
1878 
1879         dg();
1880 
1881         if (mode == serializing)
1882         {
1883             triggerEvent!(onSerializedField)(value);
1884             triggertUdaEvent!(onSerialized)(value);
1885         }
1886 
1887         else
1888         {
1889             triggerEvent!(onDeserializedField)(value);
1890             triggertUdaEvent!(onDeserialized)(value);
1891         }
1892     }
1893 
1894     private static bool isNonSerialized (T) ()
1895     {
1896         enum nonSerializedFields = collectAnnotations!(T);
1897 
1898         return ctfeContains(nonSerializedFields, "this") || getAttributes!(T).contains!(nonSerialized);
1899     }
1900 
1901     private static template hasAnnotation (T, string annotation)
1902     {
1903         enum hasAnnotation = is(typeof({ mixin("const a = T." ~ annotation ~ ";"); }));
1904     }
1905 
1906     private static string[] collectAnnotations (T) ()
1907     {
1908         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.`));
1909 
1910         static if (hasAnnotation!(T, nonSerializedField))
1911             return T.__nonSerialized;
1912 
1913         else
1914             return [];
1915     }
1916 
1917     private void error (string message, size_t line = __LINE__)
1918     {
1919         if (errorCallback)
1920             errorCallback()(new SerializationException(message, __FILE__, line));
1921     }
1922 
1923     struct Pointer (T)
1924     {
1925         T value;
1926         Id id = Id.max;
1927         Id pointee = Id.max;
1928 
1929         bool hasPointee ()
1930         {
1931             return pointee != Id.max;
1932         }
1933     }
1934 
1935     private template hasNonObjectBaseType (T)
1936     {
1937         alias BaseTypes = BaseTypeTupleOf!(T);
1938         enum hasNonObjectBaseType = BaseTypes.length > 0 &&
1939             !is(Unqual!(BaseTypes[0]) == Object);
1940     }
1941 }
1942 
1943 /**
1944  * This struct is a type independent representation of an array. This struct is used
1945  * when sending an array for archiving from the serializer to the archive.
1946  */
1947 struct Array
1948 {
1949     const(void)* ptr;
1950 
1951     /// The length of the array
1952     size_t length;
1953 
1954     /// The size of an individual element stored in the array, in bytes.
1955     size_t elementSize;
1956 
1957     /**
1958      * Returns true if the given array is a slice of the receiver.
1959      *
1960      * Params:
1961      *     b = the array to check if it's a slice
1962      *
1963      * Returns: true if the given array is a slice of the receiver.
1964      */
1965     bool isSliceOf (Array b)
1966     {
1967         return ptr >= b.ptr && ptr + length * elementSize <= b.ptr + b.length * b.elementSize;
1968     }
1969 }
1970 
1971 /**
1972  * This struct is a type independent representation of a slice. This struct is used
1973  * when sending a slice for archiving from the serializer to the archive.
1974  */
1975 struct Slice
1976 {
1977     /// The length of the slice.
1978     size_t length;
1979 
1980     /// The offset of the slice, i.e. where the slice begins in the array.
1981     size_t offset;
1982 
1983     /// The id of the slice. (Only used during unarchiving).
1984     size_t id = size_t.max;
1985 }