comparison orange/serialization/Serializer.d @ 28:bffcbc8c392b experimental

Associative arrays are now treated as references.
author Jacob Carlborg <doob@me.com>
date Fri, 19 Nov 2010 11:55:04 +0100
parents fc315d786f24
children c422ff6477dd
comparison
equal deleted inserted replaced
27:fc315d786f24 28:bffcbc8c392b
49 alias size_t Id; 49 alias size_t Id;
50 50
51 private 51 private
52 { 52 {
53 ErrorCallback errorCallback_; 53 ErrorCallback errorCallback_;
54 IArchive archive; 54 Archive archive;
55 55
56 size_t keyCounter; 56 size_t keyCounter;
57 Id idCounter; 57 Id idCounter;
58 58
59 RegisterBase[string] serializers; 59 RegisterBase[string] serializers;
70 70
71 void delegate (ArchiveException exception, string[] data) throwOnErrorCallback; 71 void delegate (ArchiveException exception, string[] data) throwOnErrorCallback;
72 void delegate (ArchiveException exception, string[] data) doNothingOnErrorCallback; 72 void delegate (ArchiveException exception, string[] data) doNothingOnErrorCallback;
73 } 73 }
74 74
75 this (IArchive archive) 75 this (Archive archive)
76 { 76 {
77 this.archive = archive; 77 this.archive = archive;
78 78
79 throwOnErrorCallback = (ArchiveException exception, string[] data) { throw exception; }; 79 throwOnErrorCallback = (ArchiveException exception, string[] data) { throw exception; };
80 doNothingOnErrorCallback = (ArchiveException exception, string[] data) { /* do nothing */ }; 80 doNothingOnErrorCallback = (ArchiveException exception, string[] data) { /* do nothing */ };
262 addSerializedArray(array, id); 262 addSerializedArray(array, id);
263 } 263 }
264 264
265 private void serializeAssociativeArray (T) (T value, string key) 265 private void serializeAssociativeArray (T) (T value, string key)
266 { 266 {
267 auto reference = getSerializedReference(value);
268
269 if (reference != Id.max)
270 return archive.archiveReference(key, reference);
271
272 Id id = nextId;
273 addSerializedReference(value, id);
274
267 string keyType = KeyTypeOfAssociativeArray!(T).stringof; 275 string keyType = KeyTypeOfAssociativeArray!(T).stringof;
268 string valueType = ValueTypeOfAssociativeArray!(T).stringof; 276 string valueType = ValueTypeOfAssociativeArray!(T).stringof;
269 277
270 archive.archiveAssociativeArray(keyType, valueType, value.length, key, nextId, { 278 archive.archiveAssociativeArray(keyType, valueType, value.length, key, id, {
271 size_t i; 279 size_t i;
272 280
273 foreach(k, v ; value) 281 foreach(k, v ; value)
274 { 282 {
275 archive.archiveAssociativeArrayKey(toData(i), { 283 archive.archiveAssociativeArrayKey(toData(i), {
539 } 547 }
540 } 548 }
541 549
542 private T deserializeAssociativeArray (T) (string key) 550 private T deserializeAssociativeArray (T) (string key)
543 { 551 {
552 auto id = deserializeReference(key);
553
554 if (auto reference = getDeserializedReference!(T)(id))
555 return *reference;
556
544 T value; 557 T value;
545 558
546 alias KeyTypeOfAssociativeArray!(T) Key; 559 alias KeyTypeOfAssociativeArray!(T) Key;
547 alias ValueTypeOfAssociativeArray!(T) Value; 560 alias ValueTypeOfAssociativeArray!(T) Value;
548 561
549 archive.unarchiveAssociativeArray(key, (size_t length) { 562 id = archive.unarchiveAssociativeArray(key, (size_t length) {
550 for (size_t i = 0; i < length; i++) 563 for (size_t i = 0; i < length; i++)
551 { 564 {
552 Key aaKey; 565 Key aaKey;
553 Value aaValue; 566 Value aaValue;
554 auto k = toData(i); 567 auto k = toData(i);
563 576
564 value[aaKey] = aaValue; 577 value[aaKey] = aaValue;
565 } 578 }
566 }); 579 });
567 580
581 addDeserializedReference(value, id);
582
568 return value; 583 return value;
569 } 584 }
570
571 /* auto id = deserializeReference(key);
572
573 if (auto reference = getDeserializedReference!(T)(id))
574 return *reference;
575
576 T value;
577 Object val = value;
578
579 archive.unarchiveObject(key, id, val, {
580 triggerEvents(deserializing, value, {
581 value = cast(T) val;
582 auto runtimeType = value.classinfo.name;
583
584 if (runtimeType in deserializers)
585 {
586 auto wrapper = getDeserializerWrapper!(T)(runtimeType);
587 wrapper(value, this, key);
588 }
589
590 else static if (isSerializable!(T, Serializer))
591 value.fromData(this, key);
592
593 else
594 {
595 if (isBaseClass(value))
596 throw new SerializationException(`The object of the static type "` ~ T.stringof ~ `" have a different runtime type (` ~ runtimeType ~ `) and therefore needs to register a deserializer for its type "` ~ runtimeType ~ `".`, __FILE__, __LINE__);
597
598 objectStructDeserializeHelper(value);
599 }
600 });
601 });
602
603 addDeserializedReference(value, id);
604
605 return value;
606 */
607 585
608 private T deserializePointer (T) (string key) 586 private T deserializePointer (T) (string key)
609 { 587 {
610 auto id = deserializeReference(key); 588 auto id = deserializeReference(key);
611 589
740 } 718 }
741 } 719 }
742 720
743 private void addSerializedReference (T) (T value, Id id) 721 private void addSerializedReference (T) (T value, Id id)
744 { 722 {
745 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); 723 static assert(isReference!(T) || isAssociativeArray!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object, pointer or associative array.`));
746 724
747 serializedReferences[cast(void*) value] = id; 725 serializedReferences[cast(void*) value] = id;
748 } 726 }
749 727
750 private void addDeserializedReference (T) (T value, Id id) 728 private void addDeserializedReference (T) (T value, Id id)
751 { 729 {
752 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); 730 static assert(isReference!(T) || isAssociativeArray!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object, pointer or associative array.`));
753 731
754 deserializedReferences[id] = cast(void*) value; 732 deserializedReferences[id] = cast(void*) value;
755 } 733 }
756 734
757 private void addDeserializedSlice (T) (T value, Id id) 735 private void addDeserializedSlice (T) (T value, Id id)
779 757
780 private T* getDeserializedSlice (T) (Slice slice) 758 private T* getDeserializedSlice (T) (Slice slice)
781 { 759 {
782 if (auto array = slice.id in deserializedSlices) 760 if (auto array = slice.id in deserializedSlices)
783 return &(cast(T) *array)[slice.offset .. slice.offset + slice.length]; // dereference the array, cast it to the right type, 761 return &(cast(T) *array)[slice.offset .. slice.offset + slice.length]; // dereference the array, cast it to the right type,
784 // slice it and then return a pointer to the result } 762 // slice it and then return a pointer to the result
785 return null; 763 return null;
786 } 764 }
787 765
788 private T* getDeserializedArray (T) (Id id) 766 private T* getDeserializedArray (T) (Id id)
789 { 767 {
954 } 932 }
955 933
956 return annotations; 934 return annotations;
957 } 935 }
958 } 936 }
959 version (none):
960 void main ()
961 {
962
963
964 void serializeObject ()
965 {
966 serializer.reset;
967 data = `<?xml version="1.0" encoding="UTF-8"?>
968 <archive type="org.dsource.orange.xml" version="1.0.0">
969 <data>
970 <struct type="B" key="0"/>
971 </data>
972 </archive>`;
973
974 serializer.serialize(B());
975 assert(archive.data == data);
976 }
977
978 void serializeStruct ()
979 {
980 serializer.reset;
981 data = `<?xml version="1.0" encoding="UTF-8"?>
982 <archive type="org.dsource.orange.xml" version="1.0.0">
983 <data>
984 <struct type="tests.Serializer.B" key="0"/>
985 </data>
986 </archive>`;
987
988 serializer.serialize(B());
989 assert(archive.data == data);
990 }
991
992 // Struct
993
994
995
996 // String
997
998 serializer.reset;
999 data = `<?xml version="1.0" encoding="UTF-8"?>
1000 <archive type="org.dsource.orange.xml" version="1.0.0">
1001 <data>
1002 <object runtimeType="orange.serialization.Serializer.C" type="C" key="0" id="0">
1003 <string type="char" length="3" key="str" id="1">foo</string>
1004 </object>
1005 </data>
1006 </archive>`;
1007
1008 auto c = new C;
1009 c.str = "foo";
1010 serializer.serialize(c);
1011 assert(archive.data == data);
1012
1013 // Deserializing
1014
1015 auto cDeserialized = serializer.deserialize!(C)(data);
1016 assert(c.str == cDeserialized.str);
1017
1018 // Array
1019
1020 serializer.reset;
1021 data = `<?xml version="1.0" encoding="UTF-8"?>
1022 <archive type="org.dsource.orange.xml" version="1.0.0">
1023 <data>
1024 <object runtimeType="orange.serialization.Serializer.D" type="D" key="0" id="0">
1025 <array type="int" length="6" key="arr" id="1">
1026 <int key="0">27</int>
1027 <int key="1">382</int>
1028 <int key="2">283</int>
1029 <int key="3">3820</int>
1030 <int key="4">32</int>
1031 <int key="5">832</int>
1032 </array>
1033 </object>
1034 </data>
1035 </archive>`;
1036
1037 auto d = new D;
1038 d.arr = [27, 382, 283, 3820, 32, 832];
1039 serializer.serialize(d);
1040 assert(archive.data == data);
1041
1042 // Deserializing
1043
1044 auto dDeserialized = serializer.deserialize!(D)(data);
1045 assert(d.arr == dDeserialized.arr);
1046
1047 // Associative Array
1048
1049 serializer.reset();
1050 data = `<?xml version="1.0" encoding="UTF-8"?>
1051 <archive type="org.dsource.orange.xml" version="1.0.0">
1052 <data>
1053 <object runtimeType="orange.serialization.Serializer.E" type="E" key="0" id="0">
1054 <associativeArray keyType="int" valueType="int" length="4" key="aa">
1055 <key key="0">
1056 <int key="0">1</int>
1057 </key>
1058 <value key="0">
1059 <int key="0">2</int>
1060 </value>
1061 <key key="1">
1062 <int key="1">3</int>
1063 </key>
1064 <value key="1">
1065 <int key="1">4</int>
1066 </value>
1067 <key key="2">
1068 <int key="2">6</int>
1069 </key>
1070 <value key="2">
1071 <int key="2">7</int>
1072 </value>
1073 <key key="3">
1074 <int key="3">39</int>
1075 </key>
1076 <value key="3">
1077 <int key="3">472</int>
1078 </value>
1079 </associativeArray>
1080 </object>
1081 </data>
1082 </archive>`;
1083
1084 auto e = new E;
1085 e.aa = [3 : 4, 1 : 2, 39 : 472, 6 : 7];
1086 serializer.serialize(e);
1087 assert(archive.data == data);
1088
1089 // Deserializing
1090
1091 auto eDeserialized = serializer.deserialize!(E)(data);
1092 //assert(e.aa == eDeserialized.aa); // cannot compare associative array
1093
1094 // Pointer
1095
1096 serializer.reset();
1097 data = `<?xml version="1.0" encoding="UTF-8"?>
1098 <archive type="org.dsource.orange.xml" version="1.0.0">
1099 <data>
1100 <object runtimeType="orange.serialization.Serializer.F" type="F" key="0" id="0">
1101 <pointer key="ptr" id="2">
1102 <int key="1">9</int>
1103 </pointer>
1104 <int key="value">9</int>
1105 </object>
1106 </data>
1107 </archive>`;
1108
1109 auto f = new F;
1110 f.value = 9;
1111 f.ptr = &f.value;
1112 serializer.serialize(f);
1113 //assert(archive.data == data); // this is not a reliable comparison, the order of int and pointer is not reliable
1114
1115 // Deserializing
1116
1117 auto fDeserialized = serializer.deserialize!(F)(data);
1118 assert(*f.ptr == *fDeserialized.ptr);
1119
1120 // Enum
1121
1122 serializer.reset();
1123 data = `<?xml version="1.0" encoding="UTF-8"?>
1124 <archive type="org.dsource.orange.xml" version="1.0.0">
1125 <data>
1126 <object runtimeType="orange.serialization.Serializer.G" type="G" key="0" id="0">
1127 <enum type="Foo" baseType="int" key="foo">1</enum>
1128 </object>
1129 </data>
1130 </archive>`;
1131
1132 auto g = new G;
1133 g.foo = Foo.b;
1134 serializer.serialize(g);
1135 assert(archive.data == data);
1136
1137 // Deserializing
1138
1139 auto gDeserialized = serializer.deserialize!(G)(data);
1140 assert(g.foo == gDeserialized.foo);
1141
1142 // Primitives
1143
1144 serializer.reset;
1145 data = `<?xml version="1.0" encoding="UTF-8"?>
1146 <archive type="org.dsource.orange.xml" version="1.0.0">
1147 <data>
1148 <object runtimeType="orange.serialization.Serializer.H" type="H" key="0" id="0">
1149 <byte key="byte_">1</byte>
1150 <char key="char_">a</char>
1151 <dchar key="dchar_">b</dchar>
1152 <double key="double_">0</double>
1153 <float key="float_">0</float>
1154 <int key="int_">1</int>
1155 <long key="long_">1</long>
1156 <real key="real_">0</real>
1157 <short key="short_">1</short>
1158 <ubyte key="ubyte_">1</ubyte>
1159 <uint key="uint_">1</uint>
1160 <ulong key="ulong_">1</ulong>
1161 <ushort key="ushort_">1</ushort>
1162 <wchar key="wchar_">c</wchar>
1163 <bool key="bool_">true</bool>
1164 </object>
1165 </data>
1166 </archive>`;
1167
1168 auto h = new H;
1169
1170 h.bool_ = true;
1171 h.byte_ = 1;
1172 h.char_ = 'a';
1173 //h.cdouble_ = 0.0 + 0.0 * 1.0i; // currently not suppported by to!()
1174 //h.cfloat_ = 0.0f + 0.0f * 1.0i; // currently not suppported by to!()
1175 //h.creal_ = 0.0 + 0.0 * 1.0i; // currently not suppported by to!()
1176 h.dchar_ = 'b';
1177 h.double_ = 0.0;
1178 h.float_ = 0.0f;
1179 //h.idouble_ = 0.0 * 1.0i; // currently not suppported by to!()
1180 //h.ifloat_ = 0.0f * 1.0i; // currently not suppported by to!()
1181 h.int_ = 1;
1182 //h.ireal_ = 0.0 * 1.0i; // currently not suppported by to!()
1183 h.long_ = 1L;
1184 h.real_ = 0.0;
1185 h.short_ = 1;
1186 h.ubyte_ = 1U;
1187 h.uint_ = 1U;
1188 h.ulong_ = 1LU;
1189 h.ushort_ = 1U;
1190 h.wchar_ = 'c';
1191
1192 serializer.serialize(h);
1193 //assert(archive.data == data); // this is not a reliable comparison
1194
1195 // Deserializing
1196
1197 auto hDeserialized = serializer.deserialize!(H)(data);
1198 assert(h == hDeserialized);
1199
1200 // Typedef
1201
1202 serializer.reset();
1203 data = `<?xml version="1.0" encoding="UTF-8"?>
1204 <archive type="org.dsource.orange.xml" version="1.0.0">
1205 <data>
1206 <object runtimeType="orange.serialization.Serializer.I" type="I" key="0" id="0">
1207 <typedef type="Int" key="a">
1208 <int key="1">1</int>
1209 </typedef>
1210 </object>
1211 </data>
1212 </archive>`;
1213
1214 auto i = new I;
1215 i.a = 1;
1216 serializer.serialize(i);
1217 assert(archive.data == data);
1218
1219 // Deserializing
1220
1221 auto iDeserialized = serializer.deserialize!(I)(data);
1222 assert(i.a == iDeserialized.a);
1223
1224 println("unit tests successful");
1225 }