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