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