comparison orange/serialization/Serializer.d @ 25:b51e953f79eb experimental

Second step in refactoring the API.
author Jacob Carlborg <doob@me.com>
date Wed, 06 Oct 2010 16:18:02 +0200
parents 9a575087b961
children 78e5fef4bbf2
comparison
equal deleted inserted replaced
24:55f0a9d5df8d 25:b51e953f79eb
31 31
32 alias Mode.serializing serializing; 32 alias Mode.serializing serializing;
33 alias Mode.deserializing deserializing; 33 alias Mode.deserializing deserializing;
34 } 34 }
35 35
36 class Serializer (ArchiveType : IArchive) 36 class Serializer
37 { 37 {
38 static assert(isArchive!(ArchiveType), format!(`The type "`, ArchiveType, `" does not implement the necessary methods to be an archive.`)); 38 alias void delegate (ArchiveException exception, IArchive.IDataType data) ErrorCallback;
39 39 alias IArchive.IDataType DataType;
40 alias ArchiveType.ErrorCallback ErrorCallback;
41 alias ArchiveType.DataType DataType;
42 40
43 private 41 private
44 { 42 {
45 ArchiveType archive; 43 ErrorCallback errorCallback_;
44 IArchive archive;
45
46 size_t keyCounter;
47 size_t idCounter;
46 48
47 RegisterBase[string] serializers; 49 RegisterBase[string] serializers;
48 RegisterBase[string] deserializers; 50 RegisterBase[string] deserializers;
49
50 size_t keyCounter;
51 51
52 bool hasBegunSerializing; 52 bool hasBegunSerializing;
53 bool hasBegunDeserializing; 53 bool hasBegunDeserializing;
54 54
55 void delegate (ArchiveException exception, DataType[] data) throwOnErrorCallback; 55 void delegate (ArchiveException exception, DataType data) throwOnErrorCallback;
56 void delegate (ArchiveException exception, DataType[] data) doNothingOnErrorCallback; 56 void delegate (ArchiveException exception, DataType data) doNothingOnErrorCallback;
57 } 57 }
58 58
59 this () 59 this (IArchive archive)
60 { 60 {
61 archive = new ArchiveType; 61 this.archive = archive;
62 62
63 throwOnErrorCallback = (ArchiveException exception, DataType[] data) { throw exception; }; 63 throwOnErrorCallback = (ArchiveException exception, IArchive.IDataType data) { throw exception; };
64 doNothingOnErrorCallback = (ArchiveException exception, DataType[] data) { /* do nothing */ }; 64 doNothingOnErrorCallback = (ArchiveException exception, IArchive.IDataType data) { /* do nothing */ };
65 65
66 setThrowOnErrorCallback(); 66 setThrowOnErrorCallback();
67 } 67 }
68
69 void registerSerializer (T) (string type, void delegate (T, Serializer, DataType) dg)
70 {
71 serializers[type] = toSerializeRegisterWrapper(dg);
72 }
73
74 void registerSerializer (T) (string type, void function (T, Serializer, DataType) func)
75 {
76 serializers[type] = toSerializeRegisterWrapper(func);
77 }
78
79 void registerDeserializer (T) (string type, void delegate (ref T, Serializer, DataType) dg)
80 {
81 deserializers[type] = toDeserializeRegisterWrapper(dg);
82 }
83
84 void registerDeserializer (T) (string type, void function (ref T, Serializer, DataType) func)
85 {
86 deserializers[type] = toDeserializeRegisterWrapper(func);
87 }
88
89 void reset ()
90 {
91 hasBegunSerializing = false;
92 hasBegunDeserializing = false;
93 resetCounters();
94
95 archive.reset;
96 }
97 68
98 ErrorCallback errorCallback () 69 ErrorCallback errorCallback ()
99 { 70 {
100 return archive.errorCallback; 71 return errorCallback_;
101 } 72 }
102 73
103 ErrorCallback errorCallback (ErrorCallback errorCallback) 74 ErrorCallback errorCallback (ErrorCallback errorCallback)
104 { 75 {
105 return archive.errorCallback = errorCallback; 76 return errorCallback_ = errorCallback;
106 } 77 }
107 78
108 void setThrowOnErrorCallback () 79 void setThrowOnErrorCallback ()
109 { 80 {
110 errorCallback = throwOnErrorCallback; 81 errorCallback = throwOnErrorCallback;
113 void setDoNothingOnErrorCallback () 84 void setDoNothingOnErrorCallback ()
114 { 85 {
115 errorCallback = doNothingOnErrorCallback; 86 errorCallback = doNothingOnErrorCallback;
116 } 87 }
117 88
118 DataType serialize (T) (T value, DataType key = null) 89 DataType serialize (T) (T value, string key = null)
119 { 90 {
120 if (!hasBegunSerializing) 91 if (!hasBegunSerializing)
121 hasBegunSerializing = true; 92 hasBegunSerializing = true;
122 93
123 serializeInternal(value, key); 94 serializeInternal(value, key);
124 archive.postProcess; 95 archive.postProcess;
125 96
126 return archive.data; 97 return archive.data;
127 } 98 }
128 99
129 private void serializeInternal (T) (T value, DataType key = null) 100 private void serializeInternal (T) (T value, string key = null)
130 { 101 {
131 if (!key) 102 if (!key)
132 key = nextKey; 103 key = nextKey;
133 104
134 archive.beginArchiving(); 105 archive.beginArchiving();
170 { 141 {
171 error: 142 error:
172 throw new SerializationException(format!(`The type "`, T, `" cannot be serialized.`), __FILE__, __LINE__); 143 throw new SerializationException(format!(`The type "`, T, `" cannot be serialized.`), __FILE__, __LINE__);
173 } 144 }
174 } 145 }
175 146
176 private void serializeObject (T) (T value, DataType key) 147 private void serializeObject (T) (T value, string key)
177 { 148 {
149 auto runtimeType = value.classinfo.name;
150
178 triggerEvents(serializing, value, { 151 triggerEvents(serializing, value, {
179 archive.archive(value, key, { 152 archive.archiveObject(runtimeType, T.stringof, key, nextId, {
180 auto runtimeType = value.classinfo.name;
181
182 if (runtimeType in serializers) 153 if (runtimeType in serializers)
183 { 154 {
184 auto wrapper = getSerializerWrapper!(T)(runtimeType); 155 auto wrapper = getSerializerWrapper!(T)(runtimeType);
185 wrapper(value, this, key); 156 wrapper(value, this, key);
186 } 157 }
196 objectStructSerializeHelper(value); 167 objectStructSerializeHelper(value);
197 } 168 }
198 }); 169 });
199 }); 170 });
200 } 171 }
201 172
202 private void serializeStruct (T) (T value, DataType key) 173 private void serializeStruct (T) (T value, DataType key)
203 { 174 {
175 auto type = T.stringof;
176
204 triggerEvents(serializing, value, { 177 triggerEvents(serializing, value, {
205 archive.archive(value, key, { 178 archive.archive(type, key, nextId, {
206 auto type = toDataType(T.stringof);
207
208 if (type in serializers) 179 if (type in serializers)
209 { 180 {
210 auto wrapper = getSerializerWrapper!(T)(type); 181 auto wrapper = getSerializerWrapper!(T)(type);
211 wrapper(value, this, key); 182 wrapper(value, this, key);
212 } 183 }
221 } 192 }
222 }); 193 });
223 }); 194 });
224 } 195 }
225 196
226 private void serializeString (T) (T value, DataType key) 197 private void serializeString (T) (T value, string key)
227 { 198 {
228 archive.archive(value, key); 199 archive.archive(value, key, nextId);
229 } 200 }
230 201
231 private void serializeArray (T) (T value, DataType key) 202 private void serializeArray (T) (T value, string key)
232 { 203 {
233 archive.archive(value, key, { 204 auto array = Array(value.ptr, value.length, BaseTypeOfArray!(T).sizeof);
205
206 archive.archiveArray(array, arrayToString!(T), key, nextId, {
234 foreach (i, e ; value) 207 foreach (i, e ; value)
235 serializeInternal(e, toDataType(i)); 208 serializeInternal(e, toDataType(i));
236 }); 209 });
237 } 210 }
238 211
239 private void serializeAssociativeArray (T) (T value, DataType key) 212 private void serializePrimitive (T) (T value, string key)
240 { 213 {
241 archive.archive(value, key, { 214 archive.archive(value, key, nextId);
242 foreach(k, v ; value)
243 serializeInternal(v, toDataType(k));
244 });
245 }
246
247 private void serializePointer (T) (T value, DataType key)
248 {
249 archive.archive(value, key, {
250 if (key in serializers)
251 {
252 auto wrapper = getSerializerWrapper!(T)(key);
253 wrapper(value, this, key);
254 }
255
256 else static if (isSerializable!(T, Serializer))
257 value.toData(this, key);
258
259 else
260 {
261 static if (isVoid!(BaseTypeOfPointer!(T)))
262 throw new SerializationException(`The value with the key "` ~ to!(string)(key) ~ `"` ~ format!(` of the type "`, T, `" cannot be serialized on its own, either implement orange.serialization.Serializable.isSerializable or register a serializer.`), __FILE__, __LINE__);
263
264 else
265 serializeInternal(*value, key);
266 }
267 });
268 }
269
270 private void serializeEnum (T) (T value, DataType key)
271 {
272 archive.archive(value, key);
273 }
274
275 private void serializePrimitive (T) (T value, DataType key)
276 {
277 archive.archive(value, key);
278 }
279
280 private void serializeTypeDef (T) (T value, DataType key)
281 {
282 archive.archive(value, key, {
283 serializeInternal!(BaseTypeOfTypeDef!(T))(value, key);
284 });
285 }
286
287 T deserialize (T) (DataType data, DataType key = null)
288 {
289 if (hasBegunSerializing && !hasBegunDeserializing)
290 resetCounters();
291
292 if (!hasBegunDeserializing)
293 hasBegunDeserializing = true;
294
295 if (!key)
296 key = nextKey;
297
298 archive.beginUnarchiving(data);
299 return deserializeInternal!(T)(key);
300 }
301
302 private T deserializeInternal (T) (DataType key)
303 {
304 static if (isTypeDef!(T))
305 return deserializeTypeDef!(T)(key);
306
307 else static if (isObject!(T))
308 return deserializeObject!(T)(key);
309
310 else static if (isStruct!(T))
311 return deserializeStruct!(T)(key);
312
313 else static if (isString!(T))
314 return deserializeString!(T)(key);
315
316 else static if (isArray!(T))
317 return deserializeArray!(T)(key);
318
319 else static if (isAssociativeArray!(T))
320 return deserializeAssociativeArray!(T)(key);
321
322 else static if (isPrimitive!(T))
323 return deserializePrimitive!(T)(key);
324
325 else static if (isPointer!(T))
326 {
327 static if (isFunctionPointer!(T))
328 goto error;
329
330 return deserializePointer!(T)(key);
331 }
332
333 else static if (isEnum!(T))
334 return deserializeEnum!(T)(key);
335
336 else
337 {
338 error:
339 throw new SerializationException(format!(`The type "`, T, `" cannot be deserialized.`), __FILE__, __LINE__);
340 }
341 }
342
343 private T deserializeObject (T) (DataType key)
344 {
345 T value = archive.unarchive!(T)(key, (T value) {
346 triggerEvents(deserializing, value, {
347 auto runtimeType = value.classinfo.name;
348
349 if (runtimeType in deserializers)
350 {
351 auto wrapper = getDeserializerWrapper!(T)(runtimeType);
352 wrapper(value, this, key);
353 }
354
355 else static if (isSerializable!(T, Serializer))
356 value.fromData(this, key);
357
358 else
359 {
360 if (isBaseClass(value))
361 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__);
362
363 objectStructDeserializeHelper(value);
364 }
365 });
366
367 return value;
368 });
369
370 return value;
371 }
372
373 private T deserializeStruct (T) (DataType key)
374 {
375 return archive.unarchive!(T)(key, (T value) {
376 triggerEvents(deserializing, value, {
377 auto type = toDataType(T.stringof);
378
379 if (type in deserializers)
380 {
381 auto wrapper = getDeserializerWrapper!(T)(type);
382 wrapper(value, this, key);
383 }
384
385 else
386 {
387 static if (isSerializable!(T, Serializer))
388 value.fromData(this, key);
389
390 else
391 objectStructDeserializeHelper(value);
392 }
393 });
394
395 return value;
396 });
397 }
398
399 private T deserializeString (T) (DataType key)
400 {
401 return archive.unarchive!(T)(key);
402 }
403
404 private T deserializeArray (T) (DataType key)
405 {
406 return archive.unarchive!(T)(key, (T value) {
407 foreach (i, ref e ; value)
408 e = deserializeInternal!(typeof(e))(toDataType(i));
409
410 return value;
411 });
412 }
413
414 private T deserializeAssociativeArray (T) (DataType key)
415 {
416 return archive.unarchive!(T)(key, (T value) {
417 foreach (k, v ; archive.unarchiveAssociativeArrayVisitor!(T))
418 value[k] = v;
419
420 return value;
421 });
422 }
423
424 private T deserializePointer (T) (DataType key)
425 {
426 return archive.unarchive!(T)(key, (T value) {
427 if (key in deserializers)
428 {
429 auto wrapper = getDeserializerWrapper!(T)(key);
430 wrapper(value, this, key);
431 }
432
433 else static if (isSerializable!(T, Serializer))
434 value.fromData(this, key);
435
436 else
437 {
438 static if (isVoid!(BaseTypeOfPointer!(T)))
439 throw new SerializationException(`The value with the key "` ~ to!(string)(key) ~ `"` ~ format!(` of the type "`, T, `" cannot be deserialized on its own, either implement orange.serialization.Serializable.isSerializable or register a deserializer.`), __FILE__, __LINE__);
440
441 else
442 *value = deserializeInternal!(BaseTypeOfPointer!(T))(key);
443 }
444
445 return value;
446 });
447 }
448
449 private T deserializeEnum (T) (DataType key)
450 {
451 return archive.unarchive!(T)(key);
452 }
453
454 private T deserializePrimitive (T) (DataType key)
455 {
456 return archive.unarchive!(T)(key);
457 }
458
459 private T deserializeTypeDef (T) (DataType key)
460 {
461 return archive.unarchive!(T)(key, (T value) {
462 return deserializeInternal!(BaseTypeOfTypeDef!(T))(key);
463 });
464 } 215 }
465 216
466 private void objectStructSerializeHelper (T) (ref T value) 217 private void objectStructSerializeHelper (T) (ref T value)
467 { 218 {
468 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.`)); 219 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.`));
509 { 260 {
510 alias BaseTypeTupleOf!(T)[0] Base; 261 alias BaseTypeTupleOf!(T)[0] Base;
511 262
512 static if (!is(Base == Object)) 263 static if (!is(Base == Object))
513 { 264 {
514 archive.archiveBaseClass!(Base)(nextKey); 265 archive.archiveBaseClass(Base.stringof, nextKey, nextId);
515 Base base = value; 266 Base base = value;
516 objectStructSerializeHelper(base); 267 objectStructSerializeHelper(base);
517 } 268 }
518 } 269 }
519 270
547 return wrapper; 298 return wrapper;
548 299
549 assert(false, "throw exception here"); 300 assert(false, "throw exception here");
550 } 301 }
551 302
552 private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void delegate (T, Serializer, DataType) dg) 303 private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void delegate (T, Serializer, string) dg)
553 { 304 {
554 return new SerializeRegisterWrapper!(T, Serializer)(dg); 305 return new SerializeRegisterWrapper!(T, Serializer)(dg);
555 } 306 }
556 307
557 private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void function (T, Serializer, DataType) func) 308 private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void function (T, Serializer, string) func)
558 { 309 {
559 return new SerializeRegisterWrapper!(T, Serializer)(func); 310 return new SerializeRegisterWrapper!(T, Serializer)(func);
560 } 311 }
561 312
562 private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void delegate (ref T, Serializer, DataType) dg) 313 private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void delegate (ref T, Serializer, string) dg)
563 { 314 {
564 return new DeserializeRegisterWrapper!(T, Serializer)(dg); 315 return new DeserializeRegisterWrapper!(T, Serializer)(dg);
565 } 316 }
566 317
567 private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void function (ref T, Serializer, DataType) func) 318 private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void function (ref T, Serializer, string) func)
568 { 319 {
569 return new DeserializeRegisterWrapper!(T, Serializer)(func); 320 return new DeserializeRegisterWrapper!(T, Serializer)(func);
570 } 321 }
571 322
572 private DataType toDataType (T) (T value) 323 private template arrayToString (T)
573 { 324 {
574 try 325 const arrayToString = BaseTypeOfArray!(T).stringof;
575 return to!(DataType)(value);
576
577 catch (ConversionException e)
578 throw new SerializationException(e);
579 } 326 }
580 327
581 private bool isBaseClass (T) (T value) 328 private bool isBaseClass (T) (T value)
582 { 329 {
583 auto name = value.classinfo.name; 330 auto name = value.classinfo.name;
584 auto index = name.lastIndexOf('.'); 331 auto index = name.lastIndexOf('.');
585 332
586 return T.stringof != name[index + 1 .. $]; 333 return T.stringof != name[index + 1 .. $];
587 } 334 }
588 335
589 private DataType nextKey () 336 private size_t nextId ()
337 {
338 return idCounter++;
339 }
340
341 private string nextKey ()
590 { 342 {
591 return toDataType(keyCounter++); 343 return toDataType(keyCounter++);
592 } 344 }
593 345
594 private void resetCounters () 346 private void resetCounters ()
595 { 347 {
596 keyCounter = 0; 348 keyCounter = 0;
349 idCounter = 0;
350 }
351
352 private string toDataType (T) (T value)
353 {
354 return to!(string)(value);
597 } 355 }
598 356
599 private void triggerEvent (string name, T) (T value) 357 private void triggerEvent (string name, T) (T value)
600 { 358 {
601 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.`)); 359 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.`));