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