diff orange/serialization/Serializer.d @ 33:4fea56a5849f experimental

Now both internal and external pointers work.
author Jacob Carlborg <doob@me.com>
date Sun, 31 Jul 2011 17:56:44 +0200
parents 9df3b7a46a51
children 068e853b9c07
line wrap: on
line diff
--- a/orange/serialization/Serializer.d	Sun Nov 21 18:51:05 2010 +0100
+++ b/orange/serialization/Serializer.d	Sun Jul 31 17:56:44 2011 +0200
@@ -49,7 +49,13 @@
 	alias size_t Id;
 	
 	private
-	{		
+	{
+		struct ValueMeta
+		{
+			Id id;
+			string key;
+		}
+		
 		ErrorCallback errorCallback_;		
 		Archive archive;
 		
@@ -66,7 +72,10 @@
 		void[][Id] deserializedSlices;
 		
 		void*[Id] serializedPointers;
-		Id[void*] serializedValues;
+		void**[Id] deserializedPointers;
+		
+		ValueMeta[void*] serializedValues;
+		void*[Id] deserializedValues;
 		
 		bool hasBegunSerializing;
 		bool hasBegunDeserializing;
@@ -142,12 +151,12 @@
 	{
 		if (!key)
 			key = nextKey;
-		
+
 		if (id == Id.max)
 			id = nextId;
-		
+
 		archive.beginArchiving();
-		
+
 		static if ( is(T == typedef) )
 			serializeTypedef(value, key, id);
 		
@@ -176,7 +185,7 @@
 				
 			else
 				serializePointer(value, key, id);
-		}			
+		}
 		
 		else static if (isEnum!(T))
 			serializeEnum(value, key, id);
@@ -303,6 +312,13 @@
 		if (!value)
 			return archive.archiveNull(T.stringof, key);
 		
+		auto reference = getSerializedReference(value);
+		
+		if (reference != Id.max)
+			return archive.archiveReference(key, reference);
+
+		addSerializedReference(value, id);
+
 		archive.archivePointer(key, id, {
 			if (key in serializers)
 			{
@@ -336,7 +352,7 @@
 	}
 	
 	private void serializePrimitive (T) (T value, string key, Id id)
-	{	
+	{
 		archive.archive(value, key, id);
 	}
 	
@@ -357,45 +373,48 @@
 		
 		if (!key)
 			key = nextKey;
-		
+
 		archive.beginUnarchiving(data);
-		return deserializeInternal!(T)(key);
+		auto value = deserializeInternal!(T)(key);
+		deserializingPostProcess;
+		
+		return value;
 	}
 	
-	private T deserializeInternal (T) (string key)
-	{
+	private T deserializeInternal (T, U) (U keyOrId)
+	{		
 		static if (isTypedef!(T))
-			return deserializeTypedef!(T)(key);
-		
+			return deserializeTypedef!(T)(keyOrId);
+
 		else static if (isObject!(T))
-			return deserializeObject!(T)(key);
+			return deserializeObject!(T)(keyOrId);
 
 		else static if (isStruct!(T))
-			return deserializeStruct!(T)(key);
+			return deserializeStruct!(T)(keyOrId);
 
 		else static if (isString!(T))
-			return deserializeString!(T)(key);
-		
+			return deserializeString!(T)(keyOrId);
+
 		else static if (isArray!(T))
-			return deserializeArray!(T)(key);
+			return deserializeArray!(T)(keyOrId);
 
 		else static if (isAssociativeArray!(T))
-			return deserializeAssociativeArray!(T)(key);
+			return deserializeAssociativeArray!(T)(keyOrId);
 
 		else static if (isPrimitive!(T))
-			return deserializePrimitive!(T)(key);
+			return deserializePrimitive!(T)(keyOrId);
 
 		else static if (isPointer!(T))
 		{			
 			static if (isFunctionPointer!(T))
 				goto error;
-			
-			return deserializePointer!(T)(key);
+			Id id;
+			return deserializePointer!(T)(keyOrId, id);
 		}		
-		
+
 		else static if (isEnum!(T))
-			return deserializeEnum!(T)(key);
-		
+			return deserializeEnum!(T)(keyOrId);
+
 		else
 		{
 			error:
@@ -403,17 +422,18 @@
 		}			
 	}
 	
-	private T deserializeObject (T) (string key)
+	private T deserializeObject (T, U) (U keyOrId)
 	{
-		auto id = deserializeReference(key);
-		
+		auto id = deserializeReference(keyOrId);
+
 		if (auto reference = getDeserializedReference!(T)(id))
 			return *reference;
 
 		T value;
 		Object val = value;
+		nextId;
 		
-		archive.unarchiveObject(key, id, val, {
+		archive.unarchiveObject(keyOrId, id, val, {
 			triggerEvents(deserializing, value, {
 				value = cast(T) val;
 				auto runtimeType = value.classinfo.name;
@@ -421,11 +441,11 @@
 				if (runtimeType in deserializers)
 				{
 					auto wrapper = getDeserializerWrapper!(T)(runtimeType);
-					wrapper(value, this, key);
+					wrapper(value, this, keyOrId);
 				}
 				
 				else static if (isSerializable!(T, Serializer))
-					value.fromData(this, key);
+					value.fromData(this, keyOrId);
 				
 				else
 				{
@@ -445,6 +465,7 @@
 	private T deserializeStruct (T) (string key)
 	{
 		T value;
+		nextId;
 		
 		archive.unarchiveStruct(key, {			
 			triggerEvents(deserializing, value, {
@@ -581,16 +602,16 @@
 		return value;
 	}
 	
-	private T deserializePointer (T) (string key)
+	private T deserializePointer (T) (string key, out Id id)
 	{
-		auto id = deserializeReference(key);
-		
+		id = deserializeReference(key);
+
 		if (auto reference = getDeserializedReference!(T)(id))
 			return *reference;
 		
 		T value = new BaseTypeOfPointer!(T);
 		
-		id = archive.unarchivePointer(key, {
+		auto pointerId = archive.unarchivePointer(key, {
 			if (key in deserializers)
 			{
 				auto wrapper = getDeserializerWrapper!(T)(key);
@@ -606,12 +627,20 @@
 					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__);
 				
 				else
-					*value = deserializeInternal!(BaseTypeOfPointer!(T))(nextKey);
+				{
+					auto k = nextKey;
+					id = deserializeReference(k);
+
+					if (id != Id.max)
+						return;
+
+					*value = deserializeInternal!(BaseTypeOfPointer!(T))(k);
+				}
 			}
 		});
-		
-		addDeserializedReference(value, id);
-		
+
+		addDeserializedReference(value, pointerId);
+
 		return value;
 	}
 	
@@ -623,13 +652,13 @@
 		mixin("return cast(T) archive.unarchiveEnum" ~ functionName ~ "(key);");
 	}
 	
-	private T deserializePrimitive (T) (string key)
-	{		
+	private T deserializePrimitive (T, U) (U keyOrId)
+	{
 		const functionName = toUpper(T.stringof[0]) ~ T.stringof[1 .. $];
-		mixin("return archive.unarchive" ~ functionName ~ "(key);");
+		mixin("return archive.unarchive" ~ functionName ~ "(keyOrId);");
 	}
 	
-	private T deserializeTypedef (T) (string key)
+	private T deserializeTypedef (T, U) (U keyOrId)
 	{
 		T value;
 		
@@ -664,8 +693,8 @@
 				alias typeof(T.tupleof[i]) Type;				
 				Type v = value.tupleof[i];				
 				auto id = nextId;
-				
-				addSerializedValue(value.tupleof[i], id);
+
+				addSerializedValue(value.tupleof[i], id, toData(keyCounter));
 				serializeInternal(v, toData(field), id);
 			}
 		}
@@ -686,11 +715,24 @@
 			static if (!internalFields.ctfeContains(field) && !nonSerializedFields.ctfeContains(field))
 			{
 				alias TypeOfField!(T, field) Type;
-				auto fieldValue = deserializeInternal!(Type)(toData(field));
-				value.tupleof[i] = fieldValue;
+				
+				static if (isPointer!(Type))
+				{
+					Id id;
+					value.tupleof[i] = deserializePointer!(Type)(toData(field), id);
+					addDeserializedPointer(value.tupleof[i], id);
+				}
+				
+				else
+				{
+					auto fieldValue = deserializeInternal!(Type)(toData(field));
+					value.tupleof[i] = fieldValue;
+				}
+
+				addDeserializedValue(value.tupleof[i], nextId);
 			}			
 		}
-		
+
 		static if (isObject!(T) && !is(T == Object))
 			deserializeBaseTypes(value);
 	}
@@ -740,9 +782,14 @@
 		deserializedSlices[id] = value;
 	}
 	
-	private void addSerializedValue (T) (ref T value, Id id)
+	private void addSerializedValue (T) (ref T value, Id id, string key)
 	{
-		serializedValues[&value] = id;
+		serializedValues[&value] = ValueMeta(id, key);
+	}
+	
+	private void addDeserializedValue (T) (ref T value, Id id)
+	{
+		deserializedValues[id] = &value;
 	}
 	
 	private void addSerializedPointer (T) (T value, Id id)
@@ -750,6 +797,11 @@
 		serializedPointers[id] = value;
 	}
 	
+	private void addDeserializedPointer (T) (ref T value, Id id)
+	{
+		deserializedPointers[id] = cast(void**) &value;
+	}
+	
 	private Id getSerializedReference (T) (T value)
 	{
 		if (auto tmp = cast(void*) value in serializedReferences)
@@ -780,6 +832,14 @@
 			return cast(T*) array;
 	}
 	
+	private T* getDeserializedValue (T) (Id id)
+	{
+		if (auto value = id in deserializedValues)
+			return cast(T*) value;
+		
+		return null;
+	}
+	
 	private T[] toSlice (T) (T[] array, Slice slice)
 	{
 		return array[slice.offset .. slice.offset + slice.length];
@@ -865,14 +925,28 @@
 	{
 		foreach (pointerId, value ; serializedPointers)
 		{
-			if (auto pointeeId = value in serializedValues)
-				archive.archivePointer(pointerId, *pointeeId);
+			if (auto valueMeta = value in serializedValues)
+				archive.archivePointer(valueMeta.id, valueMeta.key, pointerId);
 			
 			else
 				archive.postProcessPointer(pointerId);
 		}
 	}
 	
+	private void deserializingPostProcess ()
+	{
+		deserializingPostProcessPointers;
+	}
+	
+	private void deserializingPostProcessPointers ()
+	{
+		foreach (pointeeId, pointee ; deserializedValues)
+		{
+			if (auto pointer = pointeeId in deserializedPointers)
+				**pointer = pointee;
+		}
+	}
+	
 	private template arrayToString (T)
 	{
 		const arrayToString = ElementTypeOfArray!(T).stringof;
@@ -896,6 +970,11 @@
 		return toData(keyCounter++);
 	}
 	
+	private string prevKey ()
+	{
+		return toData(--keyCounter);
+	}
+	
 	private void resetCounters ()
 	{
 		keyCounter = 0;