1 /**
2  * Copyright: Copyright (c) 2010-2011 Jacob Carlborg.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Feb 6, 2010
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module mambo.serialization.archives.Archive;
8 
9 import std.conv;
10 import std.utf;
11 
12 import mambo.core._;
13 import mambo.serialization.SerializationException;
14 import mambo.serialization.Serializer;
15 import mambo.util.Traits;
16 
17 private alias ConvException ConversionException;
18 
19 /**
20  * This interface represents an archive. This is the interface all archive
21  * implementations need to implement to be able to be used as an archive with the
22  * serializer.
23  *
24  * The archive is the backend in the serialization process. It's independent of the
25  * serializer and any archive implementation. Although there are a couple of
26  * limitations of what archive types can be implemented (see below).
27  *
28  * The archive is responsible for archiving primitive types in the format chosen by
29  * the archive implementation. The archive ensures that all types are properly
30  * archived in a format that can be later unarchived.
31  *
32  * The archive can only handle primitive types, like strings, integers, floating
33  * point numbers and so on. It can not handle more complex types like objects or
34  * arrays; the serializer is responsible for breaking the complex types into
35  * primitive types that the archive can handle.
36  *
37  * Implementing an Archive Type:
38  *
39  * There are a couple of limitations when implementing a new archive, this is due
40  * to how the serializer and the archive interface is built. Except for what this
41  * interface says explicitly an archive needs to be able to handle the following:
42  *
43  * $(UL
44  * 	$(LI unarchive a value based on a key or id, regardless of where in the archive
45  * 		the value is located)
46  * $(LI most likely be able to modify already archived data)
47  * $(LI structured formats like JSON, XML and YAML works best)
48  * )
49  *
50  * If a method takes a delegate as one of its parameters that delegate should be
51  * considered as a callback to the serializer. The archive need to make sure that
52  * any archiving that is performed in the callback be a part of the type that is
53  * currently being archived. This is easiest explained by an example:
54  *
55  * ---
56  * void archiveArray (Array array, string type, string key, Id id, void delegate () dg)
57  * {
58  * 	markBegningOfNewType("array");
59  * 	storeMetadata(type, key, id);
60  *
61  * 	beginNewScope();
62  * 	dg();
63  * 	endScope();
64  *
65  * 	markEndOfType();
66  * }
67  * ---
68  *
69  * In the above example the archive have to make sure that any values archived by
70  * the callback (the delegate) get archived as an element of the array. The same
71  * principle applies to objects, structs, associative arrays and other
72  * non-primitives that accepts a delegate as a parameter.
73  *
74  * An archive implementation needs to be able to handle errors, like missing values
75  * in the serialized data, without throwing exceptions. This is because the
76  * interface of the serializer and an archive allows the user to set an error
77  * callback that is called when an error occurs; and the callback can choose to
78  * ignore the exceptions.
79  *
80  * In all the examples below "XmlArchive" is used as an example of an archive
81  * implementation. "data" is assumed to be the serialized data.
82  *
83  * When implementing a new archive type, if any of these methods do not make sense
84  * for that particular implementation just implement an empty method and return
85  * T.init, if the method returns a value.
86  */
87 interface Archive
88 {
89 	/// The type of an ID.
90 	alias size_t Id;
91 
92 	/// The typed used to represent the archived data in an untyped form.
93 	alias immutable(void)[] UntypedData;
94 
95 
96 	/**
97 	 * This is the type of an error callback which is called when an unexpected event occurs.
98 	 *
99 	 * Params:
100 	 *     exception = the exception indicating what error occurred
101 	 *     data = arbitrary data pass along, deprecated
102 	 */
103 	alias void delegate (SerializationException exception) ErrorCallback;
104 
105 	/**
106 	 * This callback will be called when an unexpected event occurs, i.e. an expected element
107 	 * is missing in the unarchiving process.
108 	 *
109 	 * Examples:
110 	 * ---
111 	 * auto archive = new XmlArchive!();
112 	 * serializer.errorCallback = (SerializationException exception) {
113 	 * 	println(exception);
114 	 * 	throw exception;
115 	 * };
116 	 * ---
117 	 */
118 	ErrorCallback errorCallback ();
119 
120 	/**
121 	 * This callback will be called when an unexpected event occurs, i.e. an expected element
122 	 * is missing in the unarchiving process.
123 	 *
124 	 * Examples:
125 	 * ---
126 	 * auto archive = new XmlArchive!();
127 	 * serializer.errorCallback = (SerializationException exception) {
128 	 * 	println(exception);
129 	 * 	throw exception;
130 	 * };
131 	 * ---
132 	 */
133 	ErrorCallback errorCallback (ErrorCallback errorCallback);
134 
135 	/// Starts the archiving process. Call this method before archiving any values.
136 	void beginArchiving ();
137 
138 	/**
139 	 * Begins the unarchiving process. Call this method before unarchiving any values.
140 	 *
141 	 * Params:
142 	 *     data = the data to unarchive
143 	 */
144 	void beginUnarchiving (UntypedData data);
145 
146 	/// Returns the data stored in the archive in an untyped form.
147 	UntypedData untypedData ();
148 
149 	/**
150 	 * Resets the archive. This resets the archive in a state making it ready to start
151 	 * a new archiving process.
152 	 */
153 	void reset ();
154 
155 	/**
156 	 * Archives an array.
157 	 *
158 	 * Examples:
159 	 * ---
160 	 * int[] arr = [1, 2, 3];
161 	 *
162 	 * auto archive = new XmlArchive!();
163 	 *
164 	 * auto a = Array(arr.ptr, arr.length, typeof(a[0]).sizeof);
165 	 *
166 	 * archive.archive(a, typeof(a[0]).string, "arr", 0, {
167 	 * 	// archive the individual elements
168 	 * });
169 	 * ---
170 	 *
171 	 * Params:
172 	 *     array = the array to archive
173 	 *     type = the runtime type of an element of the array
174 	 *     key = the key associated with the array
175 	 *     id = the id associated with the array
176 	 *     dg = a callback that performs the archiving of the individual elements
177 	 */
178 	void archiveArray (Array array, string type, string key, Id id, void delegate () dg);
179 
180 	/**
181 	 * Archives an associative array.
182 	 *
183 	 * Examples:
184 	 * ---
185 	 * int[string] arr = ["a"[] : 1, "b" : 2, "c" : 3];
186 	 *
187 	 * auto archive = new XmlArchive!();
188 	 *
189 	 * archive.archive(string.stringof, int.stringof, arr.length, "arr", 0, {
190 	 * 	// archive the individual keys and values
191 	 * });
192 	 * ---
193 	 *
194 	 *
195 	 * Params:
196 	 *     keyType = the runtime type of the keys
197 	 *     valueType = the runtime type of the values
198 	 *     length = the length of the associative array
199 	 *     key = the key associated with the associative array
200 	 *     id = the id associated with the associative array
201 	 *     dg = a callback that performs the archiving of the individual keys and values
202 	 *
203 	 * See_Also: archiveAssociativeArrayValue
204 	 * See_Also: archiveAssociativeArrayKey
205 	 */
206 	void archiveAssociativeArray (string keyType, string valueType, size_t length, string key, Id id, void delegate () dg);
207 
208 	/**
209 	 * Archives an associative array key.
210 	 *
211 	 * There are separate methods for archiving associative array keys and values
212 	 * because both the key and the value can be of arbitrary type and needs to be
213 	 * archived on its own.
214 	 *
215 	 * Examples:
216 	 * ---
217 	 * int[string] arr = ["a"[] : 1, "b" : 2, "c" : 3];
218 	 *
219 	 * auto archive = new XmlArchive!();
220 	 *
221 	 * foreach(k, v ; arr)
222 	 * {
223 	 * 	archive.archiveAssociativeArrayKey(to!(string)(i), {
224 	 * 		// archive the key
225 	 * 	});
226 	 * }
227 	 * ---
228 	 *
229 	 * The foreach statement in the above example would most likely be executed in the
230 	 * callback passed to the archiveAssociativeArray method.
231 	 *
232 	 * Params:
233 	 *     key = the key associated with the key
234 	 *     dg = a callback that performs the actual archiving of the key
235 	 *
236 	 * See_Also: archiveAssociativeArray
237 	 * See_Also: archiveAssociativeArrayValue
238 	 */
239 	void archiveAssociativeArrayKey (string key, void delegate () dg);
240 
241 	/**
242 	 * Archives an associative array value.
243 	 *
244 	 * There are separate methods for archiving associative array keys and values
245 	 * because both the key and the value can be of arbitrary type and needs to be
246 	 * archived on its own.
247 	 *
248 	 * Examples:
249 	 * ---
250 	 * int[string] arr = ["a"[] : 1, "b" : 2, "c" : 3];
251 	 *
252 	 * auto archive = new XmlArchive!();
253 	 * size_t i;
254 	 *
255 	 * foreach(k, v ; arr)
256 	 * {
257 	 * 	archive.archiveAssociativeArrayValue(to!(string)(i), {
258 	 * 		// archive the value
259 	 * 	});
260 	 *
261 	 * 	i++;
262 	 * }
263 	 * ---
264 	 *
265 	 * The foreach statement in the above example would most likely be executed in the
266 	 * callback passed to the archiveAssociativeArray method.
267 	 *
268 	 * Params:
269 	 *     key = the key associated with the value
270 	 *     dg = a callback that performs the actual archiving of the value
271 	 *
272 	 * See_Also: archiveAssociativeArray
273 	 * See_Also: archiveAssociativeArrayKey
274 	 */
275 	void archiveAssociativeArrayValue (string key, void delegate () dg);
276 
277 	/**
278 	 * Archives the given value.
279 	 *
280 	 * Example:
281 	 * ---
282 	 * enum Foo : bool
283 	 * {
284 	 * 	bar
285 	 * }
286 	 *
287 	 * auto foo = Foo.bar;
288 	 * auto archive = new XmlArchive!();
289 	 * archive.archive(foo, "bool", "foo", 0);
290 	 * ---
291 	 *
292 	 * Params:
293 	 *     value = the value to archive
294 	 *     baseType = the base type of the enum
295 	 *     key = the key associated with the value
296 	 *     id = the id associated with the value
297 	 */
298 	void archiveEnum (bool value, string baseType, string key, Id id);
299 
300 	/// Ditto
301 	void archiveEnum (bool value, string baseType, string key, Id id);
302 
303 	/// Ditto
304 	void archiveEnum (byte value, string baseType, string key, Id id);
305 
306 	/// Ditto
307 	void archiveEnum (char value, string baseType, string key, Id id);
308 
309 	/// Ditto
310 	void archiveEnum (dchar value, string baseType, string key, Id id);
311 
312 	/// Ditto
313 	void archiveEnum (int value, string baseType, string key, Id id);
314 
315 	/// Ditto
316 	void archiveEnum (long value, string baseType, string key, Id id);
317 
318 	/// Ditto
319 	void archiveEnum (short value, string baseType, string key, Id id);
320 
321 	/// Ditto
322 	void archiveEnum (ubyte value, string baseType, string key, Id id);
323 
324 	/// Ditto
325 	void archiveEnum (uint value, string baseType, string key, Id id);
326 
327 	/// Ditto
328 	void archiveEnum (ulong value, string baseType, string key, Id id);
329 
330 	/// Ditto
331 	void archiveEnum (ushort value, string baseType, string key, Id id);
332 
333 	/// Ditto
334 	void archiveEnum (wchar value, string baseType, string key, Id id);
335 
336 	/**
337 	 * Archives a base class.
338 	 *
339 	 * This method is used to indicate that the all following calls to archive a value
340 	 * should be part of the base class. This method is usually called within the
341 	 * callback passed to archiveObject. The archiveObject method can the mark the end
342 	 * of the class.
343 	 *
344 	 * Examples:
345 	 * ---
346 	 * class ArchiveBase {}
347 	 * class Foo : ArchiveBase {}
348 	 *
349 	 * auto archive = new XmlArchive!();
350 	 * archive.archiveBaseClass("ArchiveBase", "base", 0);
351 	 * ---
352 	 *
353 	 * Params:
354 	 *     type = the type of the base class to archive
355 	 *     key = the key associated with the base class
356 	 *     id = the id associated with the base class
357 	 */
358 	void archiveBaseClass (string type, string key, Id id);
359 
360 	/**
361 	 * Archives a null pointer or reference.
362 	 *
363 	 * Examples:
364 	 * ---
365 	 * int* ptr;
366 	 *
367 	 * auto archive = new XmlArchive!();
368 	 * archive.archiveNull(typeof(ptr).stringof, "ptr");
369 	 * ---
370 	 *
371 	 * Params:
372 	 *     type = the runtime type of the pointer or reference to archive
373 	 *     key = the key associated with the null pointer
374 	 */
375 	void archiveNull (string type, string key);
376 
377 	/**
378 	 * Archives an object, either a class or an interface.
379 	 *
380 	 * Examples:
381 	 * ---
382 	 * class Foo
383 	 * {
384 	 * 	int a;
385 	 * }
386 	 *
387 	 * auto foo = new Foo;
388 	 *
389 	 * auto archive = new XmlArchive!();
390 	 * archive.archiveObject(Foo.classinfo.name, "Foo", "foo", 0, {
391 	 * 	// archive the fields of Foo
392 	 * });
393 	 * ---
394 	 *
395 	 * Params:
396 	 *     runtimeType = the runtime type of the object
397 	 *     type = the static type of the object
398 	 *     key = the key associated with the object
399 	 *     id = the id associated with the object
400 	 *     dg = a callback that performs the archiving of the individual fields
401 	 */
402 	void archiveObject (string runtimeType, string type, string key, Id id, void delegate () dg);
403 
404 	/**
405 	 * Archives a pointer.
406 	 *
407 	 * If a pointer points to a value that is serialized as well, the pointer should be
408 	 * archived as a reference. Otherwise the value that the pointer points to should be
409 	 * serialized as a regular value.
410 	 *
411 	 * Examples:
412 	 * ---
413 	 * class Foo
414 	 * {
415 	 * 	int a;
416 	 * 	int* b;
417 	 * }
418 	 *
419 	 * auto foo = new Foo;
420 	 * foo.a = 3;
421 	 * foo.b = &foo.a;
422 	 *
423 	 * archive = new XmlArchive!();
424 	 * archive.archivePointer("b", 0, {
425 	 * 	// archive "foo.b" as a reference
426 	 * });
427 	 * ---
428 	 *
429 	 * ---
430 	 * int a = 3;
431 	 *
432 	 * class Foo
433 	 * {
434 	 * 	int* b;
435 	 * }
436 	 *
437 	 * auto foo = new Foo;
438 	 * foo.b = &a;
439 	 *
440 	 * archive = new XmlArchive!();
441 	 * archive.archivePointer("b", 0, {
442 	 * 	// archive "foo.b" as a regular value
443 	 * });
444 	 * ---
445 	 *
446 	 * Params:
447 	 *     key = the key associated with the pointer
448 	 *     id = the id associated with the pointer
449 	 *     dg = a callback that performs the archiving of value pointed to by the pointer
450 	 */
451 	void archivePointer (string key, Id id, void delegate () dg);
452 
453 	/**
454 	 * Archives a reference.
455 	 *
456 	 * A reference is reference to another value. For example, if an object is archived
457 	 * more than once, the first time it's archived it will actual archive the object.
458 	 * The second time the object will be archived a reference will be archived instead
459 	 * of the actual object.
460 	 *
461 	 * This method is also used when archiving a pointer that points to a value that has
462 	 * been or will be archived as well.
463 	 *
464 	 * Examples:
465 	 * ---
466 	 * class Foo {}
467 	 *
468 	 * class Bar
469 	 * {
470 	 * 	Foo f;
471 	 * 	Foo f2;
472 	 * }
473 	 *
474 	 * auto bar = new Bar;
475 	 * bar.f = new Foo;
476 	 * bar.f2 = bar.f;
477 	 *
478 	 * auto archive = new XmlArchive!();
479 	 *
480 	 * // when achiving "bar"
481 	 * archive.archiveObject(Foo.classinfo.name, "Foo", "f", 0, {});
482 	 * archive.archiveReference("f2", 0); // archive a reference to "f"
483 	 * ---
484 	 *
485 	 * Params:
486 	 *     key = the key associated with the reference
487 	 *     id = the id of the value this reference refers to
488 	 */
489 	void archiveReference (string key, Id id);
490 
491 	/**
492 	 * Archives a slice.
493 	 *
494 	 * This method should be used when archiving an array that is a slice of an
495 	 * already archived array or an array that has not yet been archived.
496 	 *
497 	 * Examples:
498 	 * ---
499 	 * auto arr = [1, 2, 3, 4];
500 	 * auto slice = arr[1 .. 3];
501 	 *
502 	 * auto archive = new XmlArchive!();
503 	 * // archive "arr" with id 0
504 	 *
505 	 * auto s = Slice(slice.length, 1);
506 	 * archive.archiveSlice(s, 1, 0);
507 	 * ---
508 	 *
509 	 * Params:
510 	 *     slice = the slice to be archived
511 	 *     sliceId = the id associated with the slice
512 	 *     arrayId = the id associated with the array this slice is a slice of
513 	 */
514 	void archiveSlice (Slice slice, Id sliceId, Id arrayId);
515 
516 	/**
517 	 * Archives a struct.
518 	 *
519 	 * Examples:
520 	 * ---
521 	 * struct Foo
522 	 * {
523 	 * 	int a;
524 	 * }
525 	 *
526 	 * auto foo = Foo(3);
527 	 *
528 	 * auto archive = new XmlArchive!();
529 	 * archive.archiveStruct(Foo.stringof, "foo", 0, {
530 	 * 	// archive the fields of Foo
531 	 * });
532 	 * ---
533 	 *
534 	 * Params:
535 	 *     type = the type of the struct
536 	 *     key = the key associated with the struct
537 	 *     id = the id associated with the struct
538 	 *     dg = a callback that performs the archiving of the individual fields
539 	 */
540 	void archiveStruct (string type, string key, Id id, void delegate () dg);
541 
542 	/**
543 	 * Archives a typedef.
544 	 *
545 	 * Examples:
546 	 * ---
547 	 * typedef int Foo;
548 	 * Foo a = 3;
549 	 *
550 	 * auto archive = new XmlArchive!();
551 	 * archive.archiveTypedef(Foo.stringof, "a", 0, {
552 	 * 	// archive "a" as the base type of Foo, i.e. int
553 	 * });
554 	 * ---
555 	 *
556 	 * Params:
557 	 *     type = the type of the typedef
558 	 *     key = the key associated with the typedef
559 	 *     id = the id associated with the typedef
560 	 *     dg = a callback that performs the archiving of the value as the base
561 	 *     		type of the typedef
562 	 */
563 	void archiveTypedef (string type, string key, Id id, void delegate () dg);
564 
565 	/**
566 	 * Archives the given value.
567 	 *
568 	 * Params:
569 	 *     value = the value to archive
570 	 *     key = the key associated with the value
571 	 *     id = the id associated wit the value
572 	 */
573 	void archive (string value, string key, Id id);
574 
575 	/// Ditto
576 	void archive (wstring value, string key, Id id);
577 
578 	/// Ditto
579 	void archive (dstring value, string key, Id id);
580 
581 	///	Ditto
582 	void archive (bool value, string key, Id id);
583 
584 	/// Ditto
585 	void archive (byte value, string key, Id id);
586 
587 
588 	//void archive (cdouble value, string key, Id id); // currently not supported by to!()
589 
590 
591 	//void archive (cent value, string key, Id id);
592 
593 	//void archive (cfloat value, string key, Id id); // currently not supported by to!()
594 
595 	/// Ditto
596 	void archive (char value, string key, Id id);
597 
598 	//void archive (creal value, string key, Id id); // currently not supported by to!()
599 
600 	/// Ditto
601 	void archive (dchar value, string key, Id id);
602 
603 	/// Ditto
604 	void archive (double value, string key, Id id);
605 
606 	/// Ditto
607 	void archive (float value, string key, Id id);
608 
609 
610 	//void archive (idouble value, string key, Id id); // currently not supported by to!()
611 
612 	//void archive (ifloat value, string key, Id id); // currently not supported by to!()
613 
614 	/// Ditto
615 	void archive (int value, string key, Id id);
616 
617 
618 	//void archive (ireal value, string key, Id id); // currently not supported by to!()
619 
620 	/// Ditto
621 	void archive (long value, string key, Id id);
622 
623 	/// Ditto
624 	void archive (real value, string key, Id id);
625 
626 	/// Ditto
627 	void archive (short value, string key, Id id);
628 
629 	/// Ditto
630 	void archive (ubyte value, string key, Id id);
631 
632 	//void archive (ucent value, string key, Id id); // currently not implemented but a reserved keyword
633 
634 	/// Ditto
635 	void archive (uint value, string key, Id id);
636 
637 	/// Ditto
638 	void archive (ulong value, string key, Id id);
639 
640 	/// Ditto
641 	void archive (ushort value, string key, Id id);
642 
643 	/// Ditto
644 	void archive (wchar value, string key, Id id);
645 
646 	/**
647 	 * Unarchives the value associated with the given key as an array.
648 	 *
649 	 * Examples:
650 	 * ---
651 	 * auto archive = new XmlArchive!();
652 	 * archive.beginUnarchiving(data);
653 	 * auto id = archive.unarchiveArray("arr", (size_t length) {
654 	 * 	auto arr = new int[length]; // pre-allocate the array
655 	 * 	// unarchive the individual elements of "arr"
656 	 * });
657 	 * ---
658 	 *
659 	 * Params:
660 	 *     key = the key associated with the array
661 	 *     dg = a callback that performs the unarchiving of the individual elements.
662 	 *     		$(I length) is the length of the archived array
663 	 *
664 	 * Returns: the id associated with the array
665 	 *
666 	 * See_Also: unarchiveArray
667 	 */
668 	Id unarchiveArray (string key, void delegate (size_t length) dg);
669 
670 	/**
671 	 * Unarchives the value associated with the given id as an array.
672 	 *
673 	 * Examples:
674 	 * ---
675 	 * auto archive = new XmlArchive!();
676 	 * archive.beginUnarchiving(data);
677 	 * archive.unarchiveArray(0, (size_t length) {
678 	 * 	auto arr = new int[length]; // pre-allocate the array
679 	 * 	// unarchive the individual elements of "arr"
680 	 * });
681 	 * ---
682 	 *
683 	 * Params:
684 	 *     id = the id associated with the value
685 	 *     dg = a callback that performs the unarchiving of the individual elements.
686 	 *     		$(I length) is the length of the archived array
687 	 *
688 	 * See_Also: unarchiveArray
689 	 */
690 	void unarchiveArray (Id id, void delegate (size_t length) dg);
691 
692 	/**
693 	 * Unarchives the value associated with the given id as an associative array.
694 	 *
695 	 * Examples:
696 	 * ---
697 	 * auto archive = new XmlArchive!();
698 	 * archive.beginUnarchiving(data);
699 	 *
700 	 * auto id = archive.unarchiveAssociativeArray("aa", (size_t length) {
701 	 * 	// unarchive the individual keys and values
702 	 * });
703 	 * ---
704 	 *
705 	 * Params:
706 	 *     key = the key associated with the associative array
707 	 *     dg = a callback that performs the unarchiving of the individual keys and values.
708 	 *     		$(I length) is the length of the archived associative array
709 	 *
710 	 * Returns: the id associated with the associative array
711 	 *
712 	 * See_Also: unarchiveAssociativeArrayKey
713 	 * See_Also: unarchiveAssociativeArrayValue
714 	 */
715 	Id unarchiveAssociativeArray (string key, void delegate (size_t length) dg);
716 
717 	/**
718 	 * Unarchives an associative array key.
719 	 *
720 	 * There are separate methods for unarchiving associative array keys and values
721 	 * because both the key and the value can be of arbitrary type and needs to be
722 	 * unarchived on its own.
723 	 *
724 	 * Examples:
725 	 * ---
726 	 * auto archive = new XmlArchive!();
727 	 * archive.beginUnarchiving(data);
728 	 *
729 	 * for (size_t i = 0; i < length; i++)
730 	 * {
731 	 * 	unarchiveAssociativeArrayKey(to!(string(i), {
732 	 * 		// unarchive the key
733 	 * 	});
734 	 * }
735 	 * ---
736 	 *
737 	 * The for statement in the above example would most likely be executed in the
738 	 * callback passed to the unarchiveAssociativeArray method.
739 	 *
740 	 * Params:
741 	 *     key = the key associated with the key
742 	 *     dg = a callback that performs the actual unarchiving of the key
743 	 *
744 	 * See_Also: unarchiveAssociativeArrayValue
745 	 * See_Also: unarchiveAssociativeArray
746 	 */
747 	void unarchiveAssociativeArrayKey (string key, void delegate () dg);
748 
749 	/**
750 	 * Unarchives an associative array value.
751 	 *
752 	 * There are separate methods for unarchiving associative array keys and values
753 	 * because both the key and the value can be of arbitrary type and needs to be
754 	 * unarchived on its own.
755 	 *
756 	 * Examples:
757 	 * ---
758 	 * auto archive = new XmlArchive!();
759 	 * archive.beginUnarchiving(data);
760 	 *
761 	 * for (size_t i = 0; i < length; i++)
762 	 * {
763 	 * 	unarchiveAssociativeArrayValue(to!(string(i), {
764 	 * 		// unarchive the value
765 	 * 	});
766 	 * }
767 	 * ---
768 	 *
769 	 * The for statement in the above example would most likely be executed in the
770 	 * callback passed to the unarchiveAssociativeArray method.
771 	 *
772 	 * Params:
773 	 *     key = the key associated with the value
774 	 *     dg = a callback that performs the actual unarchiving of the value
775 	 *
776 	 * See_Also: unarchiveAssociativeArrayKey
777 	 * See_Also: unarchiveAssociativeArray
778 	 */
779 	void unarchiveAssociativeArrayValue (string key, void delegate () dg);
780 
781 	/**
782 	 * Unarchives the value associated with the given key as a bool.
783 	 *
784 	 * This method is used when the unarchiving a enum value with the base type bool.
785 	 *
786 	 * Params:
787 	 *     key = the key associated with the value
788 	 *
789 	 * Returns: the unarchived value
790 	 */
791 	bool unarchiveEnumBool (string key);
792 
793 	/// Ditto
794 	byte unarchiveEnumByte (string key);
795 
796 	/// Ditto
797 	char unarchiveEnumChar (string key);
798 
799 	/// Ditto
800 	dchar unarchiveEnumDchar (string key);
801 
802 	/// Ditto
803 	int unarchiveEnumInt (string key);
804 
805 	/// Ditto
806 	long unarchiveEnumLong (string key);
807 
808 	/// Ditto
809 	short unarchiveEnumShort (string key);
810 
811 	/// Ditto
812 	ubyte unarchiveEnumUbyte (string key);
813 
814 	/// Ditto
815 	uint unarchiveEnumUint (string key);
816 
817 	/// Ditto
818 	ulong unarchiveEnumUlong (string key);
819 
820 	/// Ditto
821 	ushort unarchiveEnumUshort (string key);
822 
823 	/// Ditto
824 	wchar unarchiveEnumWchar (string key);
825 
826 	/**
827 	 * Unarchives the value associated with the given id as a bool.
828 	 *
829 	 * This method is used when the unarchiving a enum value with the base type bool.
830 	 *
831 	 * Params:
832 	 *     id = the id associated with the value
833 	 *
834 	 * Returns: the unarchived value
835 	 */
836 	bool unarchiveEnumBool (Id id);
837 
838 	/// Ditto
839 	byte unarchiveEnumByte (Id id);
840 
841 	/// Ditto
842 	char unarchiveEnumChar (Id id);
843 
844 	/// Ditto
845 	dchar unarchiveEnumDchar (Id id);
846 
847 	/// Ditto
848 	int unarchiveEnumInt (Id id);
849 
850 	/// Ditto
851 	long unarchiveEnumLong (Id id);
852 
853 	/// Ditto
854 	short unarchiveEnumShort (Id id);
855 
856 	/// Ditto
857 	ubyte unarchiveEnumUbyte (Id id);
858 
859 	/// Ditto
860 	uint unarchiveEnumUint (Id id);
861 
862 	/// Ditto
863 	ulong unarchiveEnumUlong (Id id);
864 
865 	/// Ditto
866 	ushort unarchiveEnumUshort (Id id);
867 
868 	/// Ditto
869 	wchar unarchiveEnumWchar (Id id);
870 
871 	/**
872 	 * Unarchives the base class associated with the given key.
873 	 *
874 	 * This method is used to indicate that the all following calls to unarchive a
875 	 * value should be part of the base class. This method is usually called within the
876 	 * callback passed to unarchiveObject. The unarchiveObject method can the mark the
877 	 * end of the class.
878 	 *
879 	 * Examples:
880 	 * ---
881 	 * auto archive = new XmlArchive!();
882 	 * archive.beginUnarchiving(data);
883 	 * archive.unarchiveBaseClass("base");
884 	 * ---
885 	 *
886 	 * Params:
887 	 *     key = the key associated with the base class.
888 	 *
889 	 * See_Also: unarchiveObject
890 	 */
891 	void unarchiveBaseClass (string key);
892 
893 	/**
894 	 * Unarchives the object associated with the given key.
895 	 *
896 	 * Examples:
897 	 * ---
898 	 * class Foo
899 	 * {
900 	 * 	int a;
901 	 * }
902 	 *
903 	 * auto archive = new XmlArchive!();
904 	 * archive.beginUnarchiving(data);
905 	 *
906 	 * Id id;
907 	 * Object o;
908 	 *
909 	 * archive.unarchiveObject("foo", id, o, {
910 	 * 	// unarchive the fields of Foo
911 	 * });
912 	 *
913 	 * auto foo = cast(Foo) o;
914 	 * ---
915 	 *
916 	 * Params:
917 	 *     key = the key associated with the object
918 	 *     id = the id associated with the object
919 	 *     result = the unarchived object
920 	 *     dg = a callback the performs the unarchiving of the individual fields
921 	 */
922 	void unarchiveObject (string key, out Id id, out Object result, void delegate () dg);
923 
924 	/**
925 	 * Unarchives the pointer associated with the given key.
926 	 *
927 	 * Examples:
928 	 * ---
929 	 * auto archive = new XmlArchive!();
930 	 * archive.beginUnarchiving(data);
931 	 * auto id = unarchivePointer("ptr", {
932 	 * 	// unarchive the value pointed to by the pointer
933 	 * });
934 	 * ---
935 	 *
936 	 * Params:
937 	 *     key = the key associated with the pointer
938 	 *     dg = a callback that performs the unarchiving of value pointed to by the pointer
939 	 *
940 	 * Returns: the id associated with the pointer
941 	 */
942 	Id unarchivePointer (string key, void delegate () dg);
943 
944 	/**
945 	 * Unarchives the reference associated with the given key.
946 	 *
947 	 * A reference is reference to another value. For example, if an object is archived
948 	 * more than once, the first time it's archived it will actual archive the object.
949 	 * The second time the object will be archived a reference will be archived instead
950 	 * of the actual object.
951 	 *
952 	 * This method is also used when unarchiving a pointer that points to a value that has
953 	 * been or will be unarchived as well.
954 	 *
955 	 * Examples:
956 	 * ---
957 	 * auto archive = new XmlArchive!();
958 	 * archive.beginUnarchiving(data);
959 	 * auto id = unarchiveReference("foo");
960 	 *
961 	 * // unarchive the value with the associated id
962 	 * ---
963 	 *
964 	 * Params:
965 	 *     key = the key associated with the reference
966 	 *
967 	 * Returns: the id the reference refers to
968 	 */
969 	Id unarchiveReference (string key);
970 
971 	/**
972 	 * Unarchives the slice associated with the given key.
973 	 *
974 	 * This method should be used when unarchiving an array that is a slice of an
975 	 * already unarchived array or an array that has not yet been unarchived.
976 	 *
977 	 * Examples:
978 	 * ---
979 	 * auto archive = new XmlArchive!();
980 	 * archive.beginUnarchiving(data);
981 	 * auto slice = unarchiveSlice("slice");
982 	 *
983 	 * // slice the original array with the help of the unarchived slice
984 	 * ---
985 	 *
986 	 * Params:
987 	 *     key = the key associated with the slice
988 	 *
989 	 * Returns: the unarchived slice
990 	 */
991 	Slice unarchiveSlice (string key);
992 
993 	/**
994 	 * Unarchives the struct associated with the given key.
995 	 *
996 	 * Examples:
997 	 * ---
998 	 * struct Foo
999 	 * {
1000 	 * 	int a;
1001 	 * }
1002 	 *
1003 	 * auto archive = new XmlArchive!();
1004 	 * archive.beginUnarchiving(data);
1005 	 * archive.unarchiveStruct("foo", {
1006 	 * 	// unarchive the fields of Foo
1007 	 * });
1008 	 * ---
1009 	 *
1010 	 * Params:
1011 	 *     key = the key associated with the string
1012 	 *     dg = a callback that performs the unarchiving of the individual fields
1013 	 */
1014 	void unarchiveStruct (string key, void delegate () dg);
1015 
1016 	/**
1017 	 * Unarchives the struct associated with the given id.
1018 	 *
1019 	 * Examples:
1020 	 * ---
1021 	 * struct Foo
1022 	 * {
1023 	 * 	int a;
1024 	 * }
1025 	 *
1026 	 * auto archive = new XmlArchive!();
1027 	 * archive.beginUnarchiving(data);
1028 	 * archive.unarchiveStruct(0, {
1029 	 * 	// unarchive the fields of Foo
1030 	 * });
1031 	 * ---
1032 	 *
1033 	 * Params:
1034 	 *     id = the id associated with the struct
1035 	 *     dg = a callback that performs the unarchiving of the individual fields.
1036 	 * 	   		The callback will receive the key the struct was archived with.
1037 	 */
1038 	void unarchiveStruct (Id id, void delegate () dg);
1039 
1040 	/**
1041 	 * Unarchives the typedef associated with the given key.
1042 	 *
1043 	 * Examples:
1044 	 * ---
1045 	 * typedef int Foo;
1046 	 * Foo foo = 3;
1047 	 *
1048 	 * auto archive = new XmlArchive!();
1049 	 * archive.beginUnarchiving(data);
1050 	 * archive.unarchiveTypedef("foo", {
1051 	 * 	// unarchive "foo" as the base type of Foo, i.e. int
1052 	 * });
1053 	 * ---
1054 	 *
1055 	 * Params:
1056 	 *     key = the key associated with the typedef
1057 	 *     dg = a callback that performs the unarchiving of the value as
1058 	 *     		 the base type of the typedef
1059 	 */
1060 	void unarchiveTypedef (string key, void delegate () dg);
1061 
1062 	/**
1063 	 * Unarchives the string associated with the given id.
1064 	 *
1065 	 * Examples:
1066 	 * ---
1067 	 * auto archive = new XmlArchive!();
1068 	 * archive.beginUnarchiving(data);
1069 	 * auto str = archive.unarchiveString(0);
1070 	 * ---
1071 	 *
1072 	 * Params:
1073 	 *     id = the id associated with the string
1074 	 *
1075 	 * Returns: the unarchived string
1076 	 */
1077 	string unarchiveString (Id id);
1078 
1079 	/// Ditto
1080 	wstring unarchiveWstring (Id id);
1081 
1082 	/// Ditto
1083 	dstring unarchiveDstring (Id id);
1084 
1085 	/**
1086 	 * Unarchives the string associated with the given key.
1087 	 *
1088 	 * Examples:
1089 	 * ---
1090 	 * auto archive = new XmlArchive!();
1091 	 * archive.beginUnarchiving(data);
1092 	 *
1093 	 * Id id;
1094 	 * auto str = archive.unarchiveString("str", id);
1095 	 * ---
1096 	 *
1097 	 * Params:
1098 	 *     id = the id associated with the string
1099 	 *
1100 	 * Returns: the unarchived string
1101 	 */
1102 	string unarchiveString (string key, out Id id);
1103 
1104 	/// Ditto
1105 	wstring unarchiveWstring (string key, out Id id);
1106 
1107 	/// Ditto
1108 	dstring unarchiveDstring (string key, out Id id);
1109 
1110 	/**
1111 	 * Unarchives the value associated with the given key.
1112 	 *
1113 	 * Examples:
1114 	 * ---
1115 	 * auto archive = new XmlArchive!();
1116 	 * archive.beginUnarchiving(data);
1117 	 * auto foo = unarchiveBool("foo");
1118 	 * ---
1119 	 * Params:
1120 	 *     key = the key associated with the value
1121 	 *
1122 	 * Returns: the unarchived value
1123 	 */
1124     bool unarchiveBool (string key);
1125 
1126 	/// Ditto
1127     byte unarchiveByte (string key);
1128 
1129     //cdouble unarchiveCdouble (string key); // currently not supported by to!()
1130     //cent unarchiveCent (string key); // currently not implemented but a reserved keyword
1131     //cfloat unarchiveCfloat (string key); // currently not supported by to!()
1132 
1133 	/// Ditto
1134     char unarchiveChar (string key); // currently not implemented but a reserved keyword
1135     //creal unarchiveCreal (string key); // currently not supported by to!()
1136 
1137     /// Ditto
1138     dchar unarchiveDchar (string key);
1139 
1140 	/// Ditto
1141     double unarchiveDouble (string key);
1142 
1143 	/// Ditto
1144     float unarchiveFloat (string key);
1145     //idouble unarchiveIdouble (string key); // currently not supported by to!()
1146     //ifloat unarchiveIfloat (string key); // currently not supported by to!()*/
1147 
1148 	/// Ditto
1149     int unarchiveInt (string key);
1150 
1151     //ireal unarchiveIreal (string key); // currently not supported by to!()
1152 
1153 	/// Ditto
1154     long unarchiveLong (string key);
1155 
1156 	/// Ditto
1157     real unarchiveReal (string key);
1158 
1159 	/// Ditto
1160     short unarchiveShort (string key);
1161 
1162 	/// Ditto
1163     ubyte unarchiveUbyte (string key);
1164 
1165 	///
1166     //ucent unarchiveCcent (string key); // currently not implemented but a reserved keyword
1167 
1168     /// Ditto
1169     uint unarchiveUint (string key);
1170 
1171 	/// Ditto
1172     ulong unarchiveUlong (string key);
1173 
1174 	/// Ditto
1175     ushort unarchiveUshort (string key);
1176 
1177 	/// Ditto
1178     wchar unarchiveWchar (string key);
1179 
1180 	/**
1181 	 * Unarchives the value associated with the given id.
1182 	 *
1183 	 * Examples:
1184 	 * ---
1185 	 * auto archive = new XmlArchive!();
1186 	 * archive.beginUnarchiving(data);
1187 	 * auto foo = unarchiveBool(0);
1188 	 * ---
1189 	 * Params:
1190 	 *     id = the id associated with the value
1191 	 *
1192 	 * Returns: the unarchived value
1193 	 */
1194 	bool unarchiveBool (Id id);
1195 
1196 	/// Ditto
1197 	byte unarchiveByte (Id id);
1198 
1199 	//cdouble unarchiveCdouble (Id id); // currently not supported by to!()
1200 	//cent unarchiveCent (Id id); // currently not implemented but a reserved keyword
1201 	//cfloat unarchiveCfloat (Id id); // currently not supported by to!()
1202 
1203 	/// Ditto
1204 	char unarchiveChar (Id id); // currently not implemented but a reserved keyword
1205 	//creal unarchiveCreal (Id id); // currently not supported by to!()
1206 
1207 	/// Ditto
1208 	dchar unarchiveDchar (Id id);
1209 
1210 	/// Ditto
1211 	double unarchiveDouble (Id id);
1212 
1213 	/// Ditto
1214 	float unarchiveFloat (Id id);
1215 	//idouble unarchiveIdouble (Id id); // currently not supported by to!()
1216 	//ifloat unarchiveIfloat (Id id); // currently not supported by to!()*/
1217 
1218 	/// Ditto
1219 	int unarchiveInt (Id id);
1220 
1221 	//ireal unarchiveIreal (Id id); // currently not supported by to!()
1222 
1223 	/// Ditto
1224 	long unarchiveLong (Id id);
1225 
1226 	/// Ditto
1227 	real unarchiveReal (Id id);
1228 
1229 	/// Ditto
1230 	short unarchiveShort (Id id);
1231 
1232 	/// Ditto
1233 	ubyte unarchiveUbyte (Id id);
1234 
1235 	///
1236 	//ucent unarchiveCcent (Id id); // currently not implemented but a reserved keyword
1237 
1238 	/// Ditto
1239 	uint unarchiveUint (Id id);
1240 
1241 	/// Ditto
1242 	ulong unarchiveUlong (Id id);
1243 
1244 	/// Ditto
1245 	ushort unarchiveUshort (Id id);
1246 
1247 	/// Ditto
1248 	wchar unarchiveWchar (Id id);
1249 
1250 	/**
1251 	 * Performs post processing of the array associated with the given id.
1252 	 *
1253 	 * Post processing can basically be anything that the archive wants to do. This
1254 	 * method is called by the serializer once for each serialized array at the end of
1255 	 * the serialization process when all values have been serialized.
1256 	 *
1257 	 * With this method the archive has a last chance of changing an archived array to
1258 	 * an archived slice instead.
1259 	 *
1260 	 * Params:
1261 	 *     id = the id associated with the array
1262 	 */
1263 	void postProcessArray (Id id);
1264 }
1265 
1266 /**
1267  * This class serves as an optional base class for archive implementations. It
1268  * contains some utility methods that can be helpful when creating a new archive
1269  * implementation.
1270  *
1271  * Most of the examples below are assumed to be in a sub class to this class and
1272  * with $(I string) as the data type.
1273  */
1274 abstract class ArchiveBase (U) : Archive
1275 {
1276 	/// The typed used to represent the archived data in a typed form.
1277 	alias immutable(U)[] Data;
1278 
1279 	private ErrorCallback errorCallback_;
1280 
1281 	/**
1282 	 * This callback will be called when an unexpected event occurs, i.e. an expected element
1283 	 * is missing in the unarchiving process.
1284 	 *
1285 	 * Examples:
1286 	 * ---
1287 	 * auto archive = new XmlArchive!();
1288 	 * serializer.errorCallback = (SerializationException exception) {
1289 	 * 	println(exception);
1290 	 * 	throw exception;
1291 	 * };
1292 	 * ---
1293 	 */
1294 	ErrorCallback errorCallback ()
1295 	{
1296 		return errorCallback_;
1297 	}
1298 
1299 	/**
1300 	 * This callback will be called when an unexpected event occurs, i.e. an expected element
1301 	 * is missing in the unarchiving process.
1302 	 *
1303 	 * Examples:
1304 	 * ---
1305 	 * auto archive = new XmlArchive!();
1306 	 * serializer.errorCallback = (SerializationException exception) {
1307 	 * 	println(exception);
1308 	 * 	throw exception;
1309 	 * };
1310 	 * ---
1311 	 */
1312 	ErrorCallback errorCallback (ErrorCallback errorCallback)
1313 	{
1314 		return errorCallback_ = errorCallback;
1315 	}
1316 
1317 	/**
1318 	 * Creates a new instance of this class with an error callback
1319 	 *
1320 	 * Params:
1321 	 *     errorCallback = the error callback used for ths instance
1322 	 */
1323 	protected this (ErrorCallback errorCallback)
1324 	{
1325 		this.errorCallback = errorCallback;
1326 	}
1327 
1328 	/**
1329 	 * Converts the given value into the type used for archiving.
1330 	 *
1331 	 * Examples:
1332 	 * ---
1333 	 * auto i = toData(3);
1334 	 * assert(i == "3");
1335 	 * ---
1336 	 *
1337 	 * Params:
1338 	 *     value = the value to convert
1339 	 *
1340 	 * Returns: the converted value
1341 	 *
1342 	 * Throws: SerializationException if the conversion failed
1343 	 * See_Also: fromData
1344 	 * See_Also: floatingPointToData
1345 	 */
1346 	protected Data toData (T) (T value)
1347 	{
1348 		try
1349 		{
1350 			static if (isFloatingPoint!(T))
1351 				return floatingPointToData(value);
1352 
1353 			else
1354 				return to!(Data)(value);
1355 		}
1356 
1357 		catch (ConversionException e)
1358 		{
1359 			error(e);
1360 			return Data.init;
1361 		}
1362 	}
1363 
1364 	/**
1365 	 * Converts the given value from the type used for archiving to $(I T).
1366 	 *
1367 	 * Examples:
1368 	 * ---
1369 	 * auto i = fromData!(int)("3");
1370 	 * assert(i == 3);
1371 	 * ---
1372 	 *
1373 	 * Params:
1374 	 * 	   T = the type to convert the given value to
1375 	 *     value = the value to convert
1376 	 *
1377 	 * Returns: the converted value
1378 	 *
1379 	 * Throws: SerializationException if the conversion failed
1380 	 * See_Also: toData
1381 	 */
1382 	protected T fromData (T, U) (const(U)[] value)
1383 	{
1384 		try
1385 		{
1386 			static if (is(T == wchar))
1387 				return toWchar(value);
1388 
1389 			else
1390 				return to!(T)(value);
1391 		}
1392 
1393 		catch (ConversionException e)
1394 		{
1395 		    error(e);
1396 		    return T.init;
1397 		}
1398 	}
1399 
1400 	/**
1401 	 * The archive is responsible for archiving primitive types in the format chosen by
1402 	 * Converts the given floating point value to the type used for archiving.
1403 	 *
1404 	 * This method is used to convert floating point values, it will convert the
1405 	 * floating point value to hexadecimal format.
1406 	 *
1407 	 * Examples:
1408 	 * ---
1409 	 * auto f = floatingPointToData(3.15f);
1410 	 * assert(f == "0xc.9999ap-2");
1411 	 * ---
1412 	 *
1413 	 * Params:
1414 	 *     value = the value to convert
1415 	 *
1416 	 * Returns: the conveted value
1417 	 *
1418 	 * Throws: SerializationException if the conversion failed
1419 	 */
1420 	protected Data floatingPointToData (T) (T value)
1421 	{
1422 		static assert(isFloatingPoint!(T), format!(`The given value of the type "`, T,
1423 			`" is not a valid type, the only valid types for this method are floating point types.`));
1424 
1425 		return to!(Data)(std..string.format("%a", value));
1426 	}
1427 
1428 	/**
1429 	 * Converts the id value to the type $(I Id).
1430 	 *
1431 	 * This method is used to conver ids stored in the serialized data to the correct
1432 	 * type.
1433 	 *
1434 	 * Params:
1435 	 *     value = the value to convert
1436 	 *
1437 	 * Returns: the converted id
1438 	 *
1439 	 * Throws: SerializationException if the converted failed
1440 	 * See_Also: fromData
1441 	 */
1442 	protected Id toId (const(U)[] value)
1443 	{
1444 		return fromData!(Id)(value);
1445 	}
1446 
1447 	/**
1448 	 * Calls the errorCallback with an exception.
1449 	 *
1450 	 * Call this method when some type of error occurred, like a field cannot be found.
1451 	 *
1452 	 * Params:
1453 	 *     message = the message for the exception
1454 	 *     file = the file where the error occurred
1455 	 *     line = the line where the error occurred
1456 	 */
1457 	protected void error (string message, string file, long line, string[] data = null)
1458 	{
1459 		if (errorCallback)
1460 			errorCallback()(new SerializationException(message));
1461 	}
1462 
1463 	/**
1464 	 * Calls the errorCallback with an exception.
1465 	 *
1466 	 * Call this method when some type of error occurred, like a field cannot be found.
1467 	 *
1468 	 * Params:
1469 	 *     exception = the exception to pass to the errorCallback
1470 	 */
1471 	protected void error (ExceptionBase exception)
1472 	{
1473 		if (errorCallback)
1474 			errorCallback()(new SerializationException(exception));
1475 	}
1476 
1477 	private wchar toWchar (const(U)[] value)
1478 	{
1479 		auto c = value.first;
1480 
1481 		if (codeLength!(wchar)(c) > 2)
1482 		    throw new ConversionException("Could not convert `" ~
1483 		        to!(string)(value) ~ "` of type " ~
1484 		        Data.stringof ~ " to type wchar.");
1485 
1486 		return cast(wchar) c;
1487 	}
1488 }