Mercurial > projects > orange
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 } |