changeset 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
files orange/serialization/Serializer.d orange/serialization/archives/Archive.d orange/serialization/archives/XMLArchive.d tests/Serializer.d
diffstat 4 files changed, 78 insertions(+), 327 deletions(-) [+]
line wrap: on
line diff
--- a/orange/serialization/Serializer.d	Fri Nov 19 11:14:55 2010 +0100
+++ b/orange/serialization/Serializer.d	Fri Nov 19 11:55:04 2010 +0100
@@ -51,7 +51,7 @@
 	private
 	{		
 		ErrorCallback errorCallback_;		
-		IArchive archive;
+		Archive archive;
 		
 		size_t keyCounter;
 		Id idCounter;
@@ -72,7 +72,7 @@
 		void delegate (ArchiveException exception, string[] data) doNothingOnErrorCallback;
 	}
 	
-	this (IArchive archive)
+	this (Archive archive)
 	{
 		this.archive = archive;
 		
@@ -264,10 +264,18 @@
 	
 	private void serializeAssociativeArray (T) (T value, string key)
 	{
+		auto reference = getSerializedReference(value);
+		
+		if (reference != Id.max)
+			return archive.archiveReference(key, reference);
+		
+		Id id = nextId;
+		addSerializedReference(value, id);
+		
 		string keyType = KeyTypeOfAssociativeArray!(T).stringof;
 		string valueType = ValueTypeOfAssociativeArray!(T).stringof;
 		
-		archive.archiveAssociativeArray(keyType, valueType, value.length, key, nextId, {
+		archive.archiveAssociativeArray(keyType, valueType, value.length, key, id, {
 			size_t i;
 			
 			foreach(k, v ; value)
@@ -541,12 +549,17 @@
 	
 	private T deserializeAssociativeArray (T) (string key)
 	{
+		auto id = deserializeReference(key);
+		
+		if (auto reference = getDeserializedReference!(T)(id))
+			return *reference;
+		
 		T value;
 		
 		alias KeyTypeOfAssociativeArray!(T) Key;
 		alias ValueTypeOfAssociativeArray!(T) Value;
 		
-		archive.unarchiveAssociativeArray(key, (size_t length) {
+		id = archive.unarchiveAssociativeArray(key, (size_t length) {
 			for (size_t i = 0; i < length; i++)
 			{
 				Key aaKey;
@@ -565,45 +578,10 @@
 			}
 		});
 		
-		return value;
-	}
-	
-	/*			auto id = deserializeReference(key);
-		
-		if (auto reference = getDeserializedReference!(T)(id))
-			return *reference;
-
-		T value;
-		Object val = value;
-		
-		archive.unarchiveObject(key, id, val, {
-			triggerEvents(deserializing, value, {
-				value = cast(T) val;
-				auto runtimeType = value.classinfo.name;
-				
-				if (runtimeType in deserializers)
-				{
-					auto wrapper = getDeserializerWrapper!(T)(runtimeType);
-					wrapper(value, this, key);
-				}
-				
-				else static if (isSerializable!(T, Serializer))
-					value.fromData(this, key);
-				
-				else
-				{
-					if (isBaseClass(value))
-						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__);
-
-					objectStructDeserializeHelper(value);					
-				}
-			});
-		});
-		
 		addDeserializedReference(value, id);
 		
 		return value;
-	 */
+	}
 	
 	private T deserializePointer (T) (string key)
 	{
@@ -742,14 +720,14 @@
 	
 	private void addSerializedReference (T) (T value, Id id)
 	{
-		static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`));
+		static assert(isReference!(T) || isAssociativeArray!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object, pointer or associative array.`));
 		
 		serializedReferences[cast(void*) value] = id;
 	}
 	
 	private void addDeserializedReference (T) (T value, Id id)
 	{
-		static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`));
+		static assert(isReference!(T) || isAssociativeArray!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object, pointer or associative array.`));
 		
 		deserializedReferences[id] = cast(void*) value;
 	}
@@ -781,7 +759,7 @@
 	{
 		if (auto array = slice.id in deserializedSlices)
 			return &(cast(T) *array)[slice.offset .. slice.offset + slice.length]; // dereference the array, cast it to the right type, 
-																		// slice it and then return a pointer to the result		}
+																				   // slice it and then return a pointer to the result
 		return null;		
 	}
 	
@@ -955,271 +933,4 @@
 		
 		return annotations;
 	}
-}
-version (none):
-	void main ()
-	{
-
-		
-		void serializeObject ()
-		{
-			serializer.reset;
-			data = `<?xml version="1.0" encoding="UTF-8"?>
-	<archive type="org.dsource.orange.xml" version="1.0.0">
-	  <data>
-	      <struct type="B" key="0"/>
-	  </data>
-	</archive>`;
-				
-			serializer.serialize(B());
-			assert(archive.data == data);
-		}
-		
-		void serializeStruct ()
-		{
-			serializer.reset;
-			data = `<?xml version="1.0" encoding="UTF-8"?>
-	<archive type="org.dsource.orange.xml" version="1.0.0">
-	  <data>
-	      <struct type="tests.Serializer.B" key="0"/>
-	  </data>
-	</archive>`;
-				
-			serializer.serialize(B());
-			assert(archive.data == data);
-		}
-		
-		// Struct
-		
-
-		
-		// String
-		
-		serializer.reset;
-		data = `<?xml version="1.0" encoding="UTF-8"?>
-	<archive type="org.dsource.orange.xml" version="1.0.0">
-	  <data>
-	      <object runtimeType="orange.serialization.Serializer.C" type="C" key="0" id="0">
-	          <string type="char" length="3" key="str" id="1">foo</string>
-	      </object>
-	  </data>
-	</archive>`;
-		
-		auto c = new C;
-		c.str = "foo";
-		serializer.serialize(c);
-		assert(archive.data == data);
-		
-		// Deserializing
-		
-		auto cDeserialized = serializer.deserialize!(C)(data);
-		assert(c.str == cDeserialized.str);
-			
-		// Array
-
-		serializer.reset;
-		data = `<?xml version="1.0" encoding="UTF-8"?>
-	<archive type="org.dsource.orange.xml" version="1.0.0">
-	  <data>
-	      <object runtimeType="orange.serialization.Serializer.D" type="D" key="0" id="0">
-	          <array type="int" length="6" key="arr" id="1">
-	              <int key="0">27</int>
-	              <int key="1">382</int>
-	              <int key="2">283</int>
-	              <int key="3">3820</int>
-	              <int key="4">32</int>
-	              <int key="5">832</int>
-	          </array>
-	      </object>
-	  </data>
-	</archive>`;
-		
-		auto d = new D;
-		d.arr = [27, 382, 283, 3820, 32, 832];
-		serializer.serialize(d);
-		assert(archive.data == data);	
-		
-		// Deserializing
-		
-		auto dDeserialized = serializer.deserialize!(D)(data);
-		assert(d.arr == dDeserialized.arr);
-		
-		// Associative Array
-		
-		serializer.reset();
-		data = `<?xml version="1.0" encoding="UTF-8"?>
-	<archive type="org.dsource.orange.xml" version="1.0.0">
-	  <data>
-	      <object runtimeType="orange.serialization.Serializer.E" type="E" key="0" id="0">
-	          <associativeArray keyType="int" valueType="int" length="4" key="aa">
-	              <key key="0">
-	                  <int key="0">1</int>
-	              </key>
-	              <value key="0">
-	                  <int key="0">2</int>
-	              </value>
-	              <key key="1">
-	                  <int key="1">3</int>
-	              </key>
-	              <value key="1">
-	                  <int key="1">4</int>
-	              </value>
-	              <key key="2">
-	                  <int key="2">6</int>
-	              </key>
-	              <value key="2">
-	                  <int key="2">7</int>
-	              </value>
-	              <key key="3">
-	                  <int key="3">39</int>
-	              </key>
-	              <value key="3">
-	                  <int key="3">472</int>
-	              </value>
-	          </associativeArray>
-	      </object>
-	  </data>
-	</archive>`;
-		
-		auto e = new E;
-		e.aa = [3 : 4, 1 : 2, 39 : 472, 6 : 7];
-		serializer.serialize(e);
-		assert(archive.data == data);
-		
-		// Deserializing
-		
-		auto eDeserialized = serializer.deserialize!(E)(data);
-		//assert(e.aa == eDeserialized.aa); // cannot compare associative array
-
-		// Pointer
-		
-		serializer.reset();
-		data = `<?xml version="1.0" encoding="UTF-8"?>
-	<archive type="org.dsource.orange.xml" version="1.0.0">
-	  <data>
-	      <object runtimeType="orange.serialization.Serializer.F" type="F" key="0" id="0">
-	          <pointer key="ptr" id="2">
-	              <int key="1">9</int>
-	          </pointer>
-	          <int key="value">9</int>
-	      </object>
-	  </data>
-	</archive>`;
-		
-		auto f = new F;
-		f.value = 9;
-		f.ptr = &f.value;
-		serializer.serialize(f);
-		//assert(archive.data == data); // this is not a reliable comparison, the order of int and pointer is not reliable
-		
-		// Deserializing
-		
-		auto fDeserialized = serializer.deserialize!(F)(data);
-		assert(*f.ptr == *fDeserialized.ptr);
-		
-		// Enum
-		
-		serializer.reset();
-		data = `<?xml version="1.0" encoding="UTF-8"?>
-	<archive type="org.dsource.orange.xml" version="1.0.0">
-	  <data>
-	      <object runtimeType="orange.serialization.Serializer.G" type="G" key="0" id="0">
-	          <enum type="Foo" baseType="int" key="foo">1</enum>
-	      </object>
-	  </data>
-	</archive>`;
-		
-		auto g = new G;
-		g.foo = Foo.b;
-		serializer.serialize(g);
-		assert(archive.data == data);
-		
-		// Deserializing
-		
-		auto gDeserialized = serializer.deserialize!(G)(data);
-		assert(g.foo == gDeserialized.foo);
-		
-		// Primitives
-		
-		serializer.reset;
-		data = `<?xml version="1.0" encoding="UTF-8"?>
-	<archive type="org.dsource.orange.xml" version="1.0.0">
-	  <data>
-	      <object runtimeType="orange.serialization.Serializer.H" type="H" key="0" id="0">
-	          <byte key="byte_">1</byte>
-	          <char key="char_">a</char>
-	          <dchar key="dchar_">b</dchar>
-	          <double key="double_">0</double>
-	          <float key="float_">0</float>
-	          <int key="int_">1</int>
-	          <long key="long_">1</long>
-	          <real key="real_">0</real>
-	          <short key="short_">1</short>
-	          <ubyte key="ubyte_">1</ubyte>
-	          <uint key="uint_">1</uint>
-	          <ulong key="ulong_">1</ulong>
-	          <ushort key="ushort_">1</ushort>
-	          <wchar key="wchar_">c</wchar>
-	          <bool key="bool_">true</bool>
-	      </object>
-	  </data>
-	</archive>`;
-		
-		auto h = new H;
-		
-		h.bool_ = true;
-		h.byte_ = 1;
-		h.char_ = 'a';
-		//h.cdouble_ = 0.0 + 0.0 * 1.0i; // currently not suppported by to!() 
-		//h.cfloat_ = 0.0f + 0.0f * 1.0i; // currently not suppported by to!() 
-		//h.creal_ = 0.0 + 0.0 * 1.0i; // currently not suppported by to!() 
-		h.dchar_ = 'b';
-		h.double_ = 0.0;
-		h.float_ = 0.0f;
-		//h.idouble_ = 0.0 * 1.0i; // currently not suppported by to!() 
-		//h.ifloat_ = 0.0f * 1.0i; // currently not suppported by to!()
-		h.int_ = 1;
-		//h.ireal_ = 0.0 * 1.0i; // currently not suppported by to!()
-		h.long_ = 1L;
-		h.real_ = 0.0;
-		h.short_ = 1;
-		h.ubyte_ = 1U;
-		h.uint_ = 1U;
-		h.ulong_ = 1LU;
-		h.ushort_ = 1U;
-		h.wchar_ = 'c';
-		
-		serializer.serialize(h);
-		//assert(archive.data == data); // this is not a reliable comparison	
-		
-		// Deserializing
-		
-		auto hDeserialized = serializer.deserialize!(H)(data);
-		assert(h == hDeserialized);
-		
-		// Typedef
-		
-		serializer.reset();
-		data = `<?xml version="1.0" encoding="UTF-8"?>
-	<archive type="org.dsource.orange.xml" version="1.0.0">
-	  <data>
-	      <object runtimeType="orange.serialization.Serializer.I" type="I" key="0" id="0">
-	          <typedef type="Int" key="a">
-	              <int key="1">1</int>
-	          </typedef>
-	      </object>
-	  </data>
-	</archive>`;
-		
-		auto i = new I;
-		i.a = 1;
-		serializer.serialize(i);
-		assert(archive.data == data);
-		
-		// Deserializing
-		
-		auto iDeserialized = serializer.deserialize!(I)(data);
-		assert(i.a == iDeserialized.a);
-
-		println("unit tests successful");
-	}
+}
\ No newline at end of file
--- a/orange/serialization/archives/Archive.d	Fri Nov 19 11:14:55 2010 +0100
+++ b/orange/serialization/archives/Archive.d	Fri Nov 19 11:55:04 2010 +0100
@@ -47,7 +47,7 @@
 	size_t id = size_t.max;
 }
 
-interface IArchive
+interface Archive
 {
 	alias Serializer.Id Id;
 	
@@ -113,7 +113,7 @@
 	
 	Id unarchiveArray (string key, void delegate (size_t length) dg);
 	void unarchiveArray (Id id, void delegate (size_t length) dg);
-	void unarchiveAssociativeArray (string type, void delegate (size_t length) dg);
+	Id unarchiveAssociativeArray (string type, void delegate (size_t length) dg);
 	void unarchiveAssociativeArrayKey (string key, void delegate () dg);
 	void unarchiveAssociativeArrayValue (string key, void delegate () dg);
 	
@@ -173,7 +173,7 @@
 	void postProcessArray (Id id);
 }
 
-abstract class Archive (U) : IArchive
+abstract class Base (U) : Archive
 {
 	version (Tango) alias U[] Data;
 	else mixin ("alias immutable(U)[] Data;");
--- a/orange/serialization/archives/XMLArchive.d	Fri Nov 19 11:14:55 2010 +0100
+++ b/orange/serialization/archives/XMLArchive.d	Fri Nov 19 11:55:04 2010 +0100
@@ -18,9 +18,9 @@
 import orange.util._;
 import orange.xml.XMLDocument;
 
-final class XMLArchive (U = char) : Archive!(U)
+final class XMLArchive (U = char) : Base!(U)
 {
-	private alias IArchive.Id Id;
+	private alias Archive.Id Id;
 	
 	private struct Tags
 	{
@@ -180,7 +180,8 @@
 			.attribute(Attributes.keyTypeAttribute, toData(keyType))
 			.attribute(Attributes.valueTypeAttribute, toData(valueType))
 			.attribute(Attributes.lengthAttribute, toData(length))
-			.attribute(Attributes.keyAttribute, key);
+			.attribute(Attributes.keyAttribute, key)
+			.attribute(Attributes.idAttribute, toData(id));
 			
 			dg();
 		};		
@@ -560,23 +561,29 @@
 		};
 	}
 	
-	void unarchiveAssociativeArray (string key, void delegate (size_t length) dg)
+	Id unarchiveAssociativeArray (string key, void delegate (size_t length) dg)
 	{
-		restore(lastElement) in {
+		return restore!(Id)(lastElement) in {
 			auto element = getElement(Tags.associativeArrayTag, key);
 			
 			if (!element.isValid)
-				return;
+				return Id.max;
 			
-			lastElement = element;
+			lastElement = element;			
 			auto len = getValueOfAttribute(Attributes.lengthAttribute);
 			
 			if (!len)
-				return;
+				return Id.max;
 			
 			auto length = fromData!(size_t)(len);
+			auto id = getValueOfAttribute(Attributes.idAttribute);
+			
+			if (!id)
+				return Id.max;
 			
 			dg(length);
+			
+			return id.toId();
 		};
 	}
 	
--- a/tests/Serializer.d	Fri Nov 19 11:14:55 2010 +0100
+++ b/tests/Serializer.d	Fri Nov 19 11:55:04 2010 +0100
@@ -246,7 +246,7 @@
 	k = new K;
 	k.a = [3 : 4, 1 : 2, 39 : 472, 6 : 7];
 	k.b = k.a;
-
+	
 	describe("Serializer") in {
 		describe("serialize object") in {
 			it("should return a serialized object") in {
@@ -330,7 +330,7 @@
 				
 				assert(archive.data().containsDefaultXmlContent());
 				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.E" type="E" key="0" id="0"`));
-				assert(archive.data().containsXmlTag("associativeArray", `keyType="int" valueType="int" length="4" key="aa"`));
+				assert(archive.data().containsXmlTag("associativeArray", `keyType="int" valueType="int" length="4" key="aa" id="1"`));
 				
 				assert(archive.data().containsXmlTag("key", `key="0"`));
 				assert(archive.data().containsXmlTag("int", `key="0"`, "1"));
@@ -497,11 +497,44 @@
 			};
 		};
 		
-		describe("associative array references") in {
-			it("should return ") in {
+		describe("serialize associative array references") in {
+			it("should return a serialized associative array and a serialized reference") in {
 				serializer.reset();
 				serializer.serialize(k);
-				println(archive.data);
+				
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.K" type="K" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("associativeArray", `keyType="int" valueType="int" length="4" key="a" id="1"`));
+				
+				assert(archive.data().containsXmlTag("key", `key="0"`));
+				assert(archive.data().containsXmlTag("int", `key="0"`, "1"));
+				assert(archive.data().containsXmlTag("value", `key="0"`));
+				assert(archive.data().containsXmlTag("int", `key="0"`, "2"));
+				
+				assert(archive.data().containsXmlTag("key", `key="1"`));
+				assert(archive.data().containsXmlTag("int", `key="1"`, "3"));
+				assert(archive.data().containsXmlTag("value", `key="1"`));
+				assert(archive.data().containsXmlTag("int", `key="1"`, "4"));
+				
+				assert(archive.data().containsXmlTag("key", `key="2"`));
+				assert(archive.data().containsXmlTag("int", `key="2"`, "6"));
+				assert(archive.data().containsXmlTag("value", `key="2"`));
+				assert(archive.data().containsXmlTag("int", `key="2"`, "7"));
+				
+				assert(archive.data().containsXmlTag("key", `key="3"`));
+				assert(archive.data().containsXmlTag("int", `key="3"`, "39"));
+				assert(archive.data().containsXmlTag("value", `key="3"`));
+				assert(archive.data().containsXmlTag("int", `key="3"`, "472"));
+
+				assert(archive.data().containsXmlTag("reference", `key="b"`, "1"));
+			};
+		};
+		
+		describe("deserialize associative array references") in {
+			it("should return two deserialized associative arrays pointing to the same data") in {
+				auto kDeserialized = serializer.deserialize!(K)(archive.data);
+				
+				assert(kDeserialized.a is kDeserialized.b);
 			};
 		};
 	};