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