changeset 0:f7b078e85f7f

First commit
author Jacob Carlborg <doob@me.com>
date Wed, 26 May 2010 17:19:13 +0200
parents
children 11a31bd929f9
files .hgignore dsss.conf orange/_.d orange/serialization/Events.d orange/serialization/RegisterWrapper.d orange/serialization/Serializable.d orange/serialization/SerializationException.d orange/serialization/Serializer.d orange/serialization/_.d orange/serialization/archives/Archive.d orange/serialization/archives/ArchiveException.d orange/serialization/archives/XMLArchive.d orange/serialization/archives/_.d orange/util/CTFE.d orange/util/Reflection.d orange/util/Traits.d orange/util/Use.d orange/util/_.d orange/util/io.d orange/util/string.d
diffstat 20 files changed, 1721 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,16 @@
+syntax: glob
+*.DS_Store
+*.o
+dsss_objs
+dsss_docs
+dsss_imports
+dsss.last
+*.orig
+*.sh
+*.a
+*.rf
+*.dylib
+main.d
+main
+*.framework
+kandil
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dsss.conf	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,1 @@
+[orange]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/_.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,13 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange._;
+
+public:
+
+import orange.serialization._;
+import orange.serialization.archives._;
+import orange.util._;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/Events.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,47 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization.Events;
+
+import orange.util._;
+
+template OnDeserialized (alias method)
+{
+	orange.serialization.Events.Event!(method) __onDeserialized;
+}
+
+template OnDeserializing (alias method)
+{
+	orange.serialization.Events.Event!(method) __onDeserializing;
+}
+
+template OnSerialized (alias method)
+{
+	orange.serialization.Events.Event!(method) __onSerialized;
+}
+
+template OnSerializing (alias method)
+{
+	orange.serialization.Events.Event!(method) __onSerializing;
+}
+
+struct Event (alias m)
+{
+	private const method = &m;
+	
+	void opCall (T) (T value)
+	{
+		void delegate () dg;
+		dg.ptr = cast(void*) value;
+		dg.funcptr = method;
+		dg();
+	}
+}
+
+package const onDeserializedField = "__onDeserialized";
+package const onDeserializingField = "__onDeserializing";
+package const onSerializedField = "__onSerialized";
+package const onSerializingField = "__onSerializing";
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/RegisterWrapper.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,69 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Feb 4, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization.RegisterWrapper;
+
+import orange.serialization.archives.Archive;
+import orange.serialization.Serializer;
+
+class RegisterBase
+{
+	
+}
+
+class SerializeRegisterWrapper (T, ArchiveType : IArchive) : RegisterBase
+{
+	private alias Serializer!(ArchiveType) SerializerType;
+	private alias SerializerType.DataType DataType;
+	private void delegate (T, SerializerType, DataType) dg;
+	private void function (T, SerializerType, DataType) func;
+
+	this (void delegate (T, SerializerType, DataType) dg)
+	{
+		this.dg = dg;
+	}
+
+	this (void function (T, SerializerType, DataType) func)
+	{
+		this.func = func;
+	}
+
+	void opCall (T value, SerializerType archive, DataType key)
+	{
+		if (dg)
+			dg(value, archive, key);
+		
+		else if (func)
+			func(value, archive, key);
+	}
+}
+
+class DeserializeRegisterWrapper (T, ArchiveType : IArchive) : RegisterBase
+{
+	private alias Serializer!(ArchiveType) SerializerType;
+	private alias SerializerType.DataType DataType;
+	private void delegate (ref T, SerializerType, DataType) dg;
+	private void function (ref T, SerializerType, DataType) func;
+
+	this (void delegate (ref T, SerializerType, DataType) dg)
+	{
+		this.dg = dg;
+	}
+
+	this (void function (ref T, SerializerType, DataType) func)
+	{
+		this.func = func;
+	}
+
+	void opCall (ref T value, SerializerType archive, DataType key)
+	{
+		if (dg)
+			dg(value, archive, key);
+		
+		if (func)
+			func(value, archive, key);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/Serializable.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,58 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization.Serializable;
+
+import orange.serialization.archives.Archive;
+import orange.serialization.Events;
+import orange.util.CTFE;
+
+template Serializable ()
+{
+	void toData (T) (T archive, T.DataType key)
+	{		
+		alias typeof(this) ThisType;
+		
+		foreach (i, dummy ; typeof(T.tupleof))
+		{
+			alias typeof(ThisType.tupleof[i]) FieldType;
+			
+			const field = nameOfFieldAt!(ThisType, i);			
+			auto value = getValueOfField!(ThisType, FieldType, field)(this);
+			
+			archive.archive(value, field);
+		}
+	}
+	
+	void fromData (T) (T archive, T.DataType key)
+	{
+		alias typeof(this) ThisType;
+		
+		foreach (i, dummy ; typeof(ThisType.tupleof))
+		{
+			alias typeof(ThisType.tupleof[i]) FieldType;
+			
+			const field = nameOfFieldAt!(ThisType, i);
+			auto value = archive.unarchive!(FieldType)(field);
+			
+			setValueOfField!(FieldType, ThisType, field)(this, value);
+		}
+	}
+}
+
+template NonSerialized (alias field)
+{
+	NonSerializedField!(field) __nonSerialized;
+}
+
+struct NonSerializedField (alias f)
+{
+	const field = f.stringof;
+}
+
+package const nonSerializedField = "__nonSerialized";
+package const serializedField = "__serialized";
+package const internalFields = [nonSerializedField[], onDeserializedField, onDeserializingField, onSerializedField, onSerializingField];
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/SerializationException.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,31 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 30, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization.SerializationException;
+
+import orange.util.string;
+
+class SerializationException : Exception
+{	
+	this (string message)
+	{
+		super(message);
+	}
+	
+	this (string message, string file, long line)
+	{
+		version (Tango)
+			super(message, file, line);
+		
+		else
+			super(message);
+	}
+	
+	this (Exception exception)
+	{
+		super(exception.msg, exception.file, exception.line, exception.next, exception.info);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/Serializer.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,606 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization.Serializer;
+
+version (Tango)
+{
+	import tango.util.Convert : to, ConversionException;
+}
+
+import orange.serialization._;
+import orange.serialization.archives._;
+import orange.util._;
+
+private
+{
+	alias orange.util.CTFE.contains ctfeContains;
+	
+	private enum Mode
+	{
+		serializing,
+		deserializing
+	}
+	
+	alias Mode.serializing serializing;
+	alias Mode.deserializing deserializing;
+}
+
+class Serializer (ArchiveType : IArchive)
+{
+	static assert(isArchive!(ArchiveType), format!(`The type "`, ArchiveType, `" does not implement the necessary methods to be an archive.`));
+	
+	private
+	{
+		ArchiveType archive;
+		alias ArchiveType.DataType DataType;
+		
+		RegisterBase[string] serializers;
+		RegisterBase[string] deserializers;
+		
+		size_t keyCounter;
+		
+		bool hasBegunSerializing;
+		bool hasBegunDeserializing;
+	}
+	
+	this ()
+	{
+		archive = new ArchiveType;
+	}
+
+	void registerSerializer (T) (string type, void delegate (T, Serializer, DataType) dg)
+	{		
+		serializers[type] = toSerializeRegisterWrapper(dg);
+	}
+
+	void registerSerializer (T) (string type, void function (T, Serializer, DataType) func)
+	{		
+		serializers[type] = toSerializeRegisterWrapper(func);
+	}
+
+	void registerDeserializer (T) (string type, void delegate (ref T, Serializer, DataType) dg)
+	{		
+		deserializers[type] = toDeserializeRegisterWrapper(dg);
+	}
+
+	void registerDeserializer (T) (string type, void function (ref T, Serializer, DataType) func)
+	{		
+		deserializers[type] = toDeserializeRegisterWrapper(func);
+	}
+	
+	void reset ()
+	{
+		hasBegunSerializing = false;
+		hasBegunDeserializing = false;
+		resetCounters();
+		
+		archive.reset;
+	}
+	
+	DataType serialize (T) (T value, DataType key = null)
+	{
+		if (!hasBegunSerializing)
+			hasBegunSerializing = true;
+		
+		if (!key)
+			key = nextKey;
+		
+		archive.beginArchiving();
+		
+		static if (isTypeDef!(T))
+			serializeTypeDef(value, key);
+		
+		static if (isObject!(T))
+			serializeObject(value, key);
+
+		else static if (isStruct!(T))
+			serializeStruct(value, key);
+
+		else static if (isString!(T))
+			serializeString(value, key);
+		
+		else static if (isArray!(T))
+			serializeArray(value, key);
+
+		else static if (isAssociativeArray!(T))
+			serializeAssociativeArray(value, key);
+
+		else static if (isPrimitive!(T))
+			serializePrimitive(value, key);
+
+		else static if (isPointer!(T))
+		{
+			static if (isFunctionPointer!(T))
+				static assert(false, format!(`The type "`, T, `" cannot be serialized.`));
+				
+			else
+				serializePointer(value, key);
+		}
+			
+		
+		else static if (isEnum!(T))
+			serializeEnum(value, key);
+		
+		else
+			static assert(false, format!(`The type "`, T, `" cannot be serialized.`));
+		
+		return archive.data;
+	}
+	
+	private void serializeObject (T) (T value, DataType key)
+	{		
+		auto nonSerializedFields = collectAnnotations!(nonSerializedField)(value);
+		
+		triggerEvents(serializing, value, {
+			archive.archive(value, key, {
+				auto runtimeType = value.classinfo.name;
+
+				if (runtimeType in serializers)
+				{
+					auto wrapper = getSerializerWrapper!(T)(runtimeType);
+					wrapper(value, this, key);
+				}
+				
+				else static if (isSerializable!(T, ArchiveType))
+					value.toData(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 serializer for its type "` ~ runtimeType ~ `".`, __FILE__, __LINE__);
+				
+					objectStructSerializeHelper(value, nonSerializedFields);
+				}
+			});
+		});
+	}
+
+	private void serializeStruct (T) (T value, DataType key)
+	{		
+		auto nonSerializedFields = collectAnnotations!(nonSerializedField)(value);
+		
+		triggerEvents(serializing, value, {
+			archive.archive(value, key, {
+				auto type = toDataType(T.stringof);
+				
+				if (type in serializers)
+				{
+					auto wrapper = getSerializerWrapper!(T)(type);
+					wrapper(value, this, key);
+				}
+				
+				else
+				{
+					static if (isSerializable!(T, ArchiveType))
+						value.toData(this, key);
+					
+					else
+						objectStructSerializeHelper(value, nonSerializedFields);
+				}
+			});
+		});
+	}
+	
+	private void serializeString (T) (T value, DataType key)
+	{
+		archive.archive(value, key);
+	}
+
+	private void serializeArray (T) (T value, DataType key)
+	{		
+		archive.archive(value, key, {
+			foreach (i, e ; value)
+				archive.archive(e, toDataType(i));
+		});
+	}
+
+	private void serializeAssociativeArray (T) (T value, DataType key)
+	{
+		archive.archive(value, key, {
+			foreach(k, v ; value)
+				archive.archive(v, toDataType(k));
+		});
+	}
+
+	private void serializePointer (T) (T value, DataType key)
+	{
+		archive.archive(value, key, {
+			if (key in serializers)
+			{
+				auto wrapper = getSerializerWrapper!(T)(key);
+				wrapper(value, this, key);
+			}
+			
+			else static if (isSerializable!(T, ArchiveType))
+				value.toData(this, key);
+			
+			else
+			{
+				static if (isVoid!(BaseTypeOfPointer!(T)))
+					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__);
+				
+				else
+					serialize(*value, key);
+			}				
+		});
+	}
+	
+	private void serializeEnum (T) (T value, DataType key)
+	{
+		archive.archive(value, key);
+	}
+
+	private void serializePrimitive (T) (T value, DataType key)
+	{		
+		archive.archive(value, key);
+	}
+	
+	private void serializeTypeDef (T) (T value, DataType key)
+	{
+		archive.archive(value, key, {
+			serialize!(BaseTypeOfTypeDef!(T))(value, key);
+		});
+	}
+	
+	T deserialize (T) (DataType data, DataType key = null)
+	{		
+		if (hasBegunSerializing && !hasBegunDeserializing)
+			resetCounters();
+		
+		if (!hasBegunDeserializing)
+			hasBegunDeserializing = true;
+		
+		if (!key)
+			key = nextKey;
+		
+		archive.beginUnarchiving(data);
+		return deserializeInternal!(T)(key);
+	}
+	
+	private T deserializeInternal (T) (DataType key)
+	{
+		static if (isTypeDef!(T))
+			return deserializeTypeDef!(T)(key);
+		
+		else static if (isObject!(T))
+			return deserializeObject!(T)(key);
+
+		else static if (isStruct!(T))
+			return deserializeStruct!(T)(key);
+
+		else static if (isString!(T))
+			return deserializeString!(T)(key);
+		
+		else static if (isArray!(T))
+			return deserializeArray!(T)(key);
+
+		else static if (isAssociativeArray!(T))
+			return deserializeAssociativeArray!(T)(key);
+
+		else static if (isPrimitive!(T))
+			return deserializePrimitive!(T)(key);
+
+		else static if (isPointer!(T))
+			return deserializePointer!(T)(key);
+		
+		else static if (isEnum!(T))
+			return deserializeEnum!(T)(key);
+		
+		else
+			static assert(false, format!(`The type "`, T, `" cannot be deserialized.`));
+	}
+
+	private T deserializeObject (T) (DataType key)
+	{		
+		T value = archive.unarchive!(T)(key, (T value) {
+			auto nonSerializedFields = collectAnnotations!(nonSerializedField)(value);
+			
+			triggerEvents(deserializing, value, {
+				auto runtimeType = value.classinfo.name;
+				
+				if (runtimeType in deserializers)
+				{
+					auto wrapper = getDeserializerWrapper!(T)(runtimeType);
+					wrapper(value, this, key);
+				}
+				
+				else static if (isSerializable!(T, ArchiveType))
+					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, nonSerializedFields);					
+				}
+			});
+			
+			return value;
+		});
+		
+		return value;
+	}
+
+	private T deserializeStruct (T) (DataType key)
+	{		
+		return archive.unarchive!(T)(key, (T value) {			
+			auto nonSerializedFields = collectAnnotations!(nonSerializedField)(value);
+			
+			triggerEvents(deserializing, value, {
+				auto type = toDataType(T.stringof);
+				
+				if (type in deserializers)
+				{
+					auto wrapper = getDeserializerWrapper!(T)(type);
+					wrapper(value, this, key);
+				}
+				
+				else
+				{
+					static if (isSerializable!(T, ArchiveType))
+						value.fromData(this, key);
+					
+					else
+						objectStructDeserializeHelper(value, nonSerializedFields);
+				}	
+			});
+			
+			return value;
+		});
+	}
+	
+	private T deserializeString (T) (DataType key)
+	{
+		return archive.unarchive!(T)(key);
+	}
+
+	private T deserializeArray (T) (DataType key)
+	{
+		return archive.unarchive!(T)(key, (T value) {
+			foreach (i, ref e ; value)
+				e = archive.unarchive!(typeof(e))(toDataType(i));
+			
+			return value;
+		});	
+	}
+
+	private T deserializeAssociativeArray (T) (DataType key)
+	{		
+		return archive.unarchive!(T)(key, (T value) {			
+			foreach (k, v ; archive.unarchiveAssociativeArrayVisitor!(T))
+				value[k] = v;
+			
+			return value;
+		});	
+	}
+
+	private T deserializePointer (T) (DataType key)
+	{
+		return archive.unarchive!(T)(key, (T value) {
+			if (key in deserializers)
+			{
+				auto wrapper = getDeserializerWrapper!(T)(key);
+				wrapper(value, this, key);
+			}
+			
+			else static if (isSerializable!(T, ArchiveType))
+				value.fromData(this, key);
+			
+			else
+			{
+				static if (isVoid!(BaseTypeOfPointer!(T)))
+					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))(key);
+			}
+			
+			return value;
+		});
+	}
+	
+	private T deserializeEnum (T) (DataType key)
+	{
+		return archive.unarchive!(T)(key);
+	}
+
+	private T deserializePrimitive (T) (DataType key)
+	{		
+		return archive.unarchive!(T)(key);
+	}
+	
+	private T deserializeTypeDef (T) (DataType key)
+	{
+		return archive.unarchive!(T)(key, (T value) {
+			return deserializeInternal!(BaseTypeOfTypeDef!(T))(key);
+		});
+	}
+	
+	private void objectStructSerializeHelper (T) (T value, string[] nonSerializedFields)
+	{
+		foreach (i, dummy ; typeof(T.tupleof))
+		{
+			const field = nameOfFieldAt!(T, i);
+			
+			if (!internalFields.ctfeContains(field) && !nonSerializedFields.ctfeContains(field))
+			{
+				alias typeof(T.tupleof[i]) Type;
+				
+				Type v = value.tupleof[i];
+				
+				//Type v = getValueOfField!(T, Type, field)(value);
+				serialize(v, toDataType(field));
+			}				
+		}
+		
+		static if (is(T : Object) && !is(T == Object))
+			serializeBaseTypes(value, nonSerializedFields);
+	}
+	
+	private void objectStructDeserializeHelper (T) (T value, string[] nonSerializedFields)
+	{		
+		foreach (i, dummy ; typeof(T.tupleof))
+		{
+			const field = nameOfFieldAt!(T, i);
+						
+			if (!internalFields.ctfeContains(field) && !nonSerializedFields.ctfeContains(field))
+			{							
+				alias TypeOfField!(T, field) Type;
+				auto fieldValue = deserializeInternal!(Type)(toDataType(field));					
+				setValueOfField!(T, Type, field)(value, fieldValue);
+			}			
+		}
+		
+		static if (is(T : Object) && !is(T == Object))
+			deserializeBaseTypes(value, nonSerializedFields);
+	}
+	
+	private void serializeBaseTypes (T : Object) (T value, string[] nonSerializedFields)
+	{
+		alias BaseTypeTupleOf!(T)[0] Base;
+		
+		static if (!is(Base == Object))
+		{
+			archive.archiveBaseClass!(Base)(nextKey);
+			objectStructSerializeHelper!(Base)(value, nonSerializedFields);
+		}
+	}
+	
+	private void deserializeBaseTypes (T : Object) (T value, string[] nonSerializedFields)
+	{
+		alias BaseTypeTupleOf!(T)[0] Base;
+		
+		static if (!is(Base == Object))
+		{
+			archive.unarchiveBaseClass!(Base)(nextKey);
+			objectStructDeserializeHelper!(Base)(value, nonSerializedFields);
+		}
+	}
+	
+	private SerializeRegisterWrapper!(T, ArchiveType) getSerializerWrapper (T) (string type)
+	{
+		auto wrapper = cast(SerializeRegisterWrapper!(T, ArchiveType)) serializers[type];
+		
+		if (wrapper)
+			return wrapper;
+		
+		assert(false, "throw exception here");
+	}
+
+	private DeserializeRegisterWrapper!(T, ArchiveType) getDeserializerWrapper (T) (string type)
+	{
+		auto wrapper = cast(DeserializeRegisterWrapper!(T, ArchiveType)) deserializers[type];
+		
+		if (wrapper)
+			return wrapper;
+		
+		assert(false, "throw exception here");
+	}
+	
+	private SerializeRegisterWrapper!(T, ArchiveType) toSerializeRegisterWrapper (T) (void delegate (T, Serializer, DataType) dg)
+	{		
+		return new SerializeRegisterWrapper!(T, ArchiveType)(dg);
+	}
+
+	private SerializeRegisterWrapper!(T, ArchiveType) toSerializeRegisterWrapper (T) (void function (T, Serializer, DataType) func)
+	{		
+		return new SerializeRegisterWrapper!(T, ArchiveType)(func);
+	}
+
+	private DeserializeRegisterWrapper!(T, ArchiveType) toDeserializeRegisterWrapper (T) (void delegate (ref T, Serializer, DataType) dg)
+	{		
+		return new DeserializeRegisterWrapper!(T, ArchiveType)(dg);
+	}
+
+	private DeserializeRegisterWrapper!(T, ArchiveType) toDeserializeRegisterWrapper (T) (void function (ref T, Serializer, DataType) func)
+	{		
+		return new DeserializeRegisterWrapper!(T, ArchiveType)(func);
+	}
+	
+	private DataType toDataType (T) (T value)
+	{
+		try
+			return to!(DataType)(value);
+		
+		catch (ConversionException e)
+			throw new SerializationException(e);
+	}
+	
+	private bool isBaseClass (T) (T value)
+	{
+		auto name = value.classinfo.name;		
+		auto index = name.lastIndexOf('.');
+		
+		return T.stringof != name[index + 1 .. $];
+	}
+	
+	private DataType nextKey ()
+	{
+		return toDataType(keyCounter++);
+	}
+	
+	private void resetCounters ()
+	{
+		keyCounter = 0;
+	}
+	
+	private void triggerEvent (string name, T) (T value)
+	{
+		static assert (is(T == class) || is(T == struct), format!(`The given value of the type "`, T, `" is not a valid type, the only valid types for this method are classes and structs.`));
+		
+		foreach (i, dummy ; typeof(T.tupleof))
+		{
+			const field = nameOfFieldAt!(T, i);
+			
+			static if (field == name)
+			{
+				alias TypeOfField!(T, field) Type;
+				auto event = getValueOfField!(T, Type, field)(value);
+				event(value);
+			}
+		}
+	}
+	
+	private void triggerEvents (T) (Mode mode, T value, void delegate () dg)
+	{
+		if (mode == serializing)
+			triggerEvent!(onSerializingField)(value);
+		
+		else
+			triggerEvent!(onDeserializingField)(value);
+		
+		dg();
+		
+		if (mode == serializing)
+			triggerEvent!(onSerializedField)(value);
+		
+		else
+			triggerEvent!(onDeserializedField)(value);
+	}
+	
+	private string[] collectAnnotations (string name, T) (T value)
+	{
+		static assert (is(T == class) || is(T == struct), format!(`The given value of the type "`, T, `" is not a valid type, the only valid types for this method are classes and structs.`));
+		
+		string[] annotations;
+		
+		foreach (i, dummy ; typeof(T.tupleof))
+		{
+			const field = nameOfFieldAt!(T, i);
+			
+			static if (field == name)
+			{
+				alias TypeOfField!(T, field) Type;
+				auto f = getValueOfField!(T, Type, field)(value);
+				annotations ~= f.field;
+			}
+		}
+		
+		return annotations;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/_.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,15 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization._;
+
+public:
+	
+import orange.serialization.Events;
+import orange.serialization.RegisterWrapper;
+import orange.serialization.Serializable;
+import orange.serialization.SerializationException;
+import orange.serialization.Serializer;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/archives/Archive.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,46 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Feb 6, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization.archives.Archive;
+
+version (Tango)
+	import tango.util.Convert;
+
+import orange.serialization.archives.ArchiveException;
+
+interface IArchive
+{
+	void beginArchiving ();
+	void reset ();
+}
+
+abstract class Archive (U) : IArchive
+{
+	alias U[] DataType;
+	
+	abstract void beginArchiving ();
+	abstract void beginUnarchiving (DataType data);
+	abstract DataType data ();
+	abstract void reset ();
+	
+	protected DataType toDataType (T) (T value)
+	{
+		try
+			return to!(DataType)(value);
+		
+		catch (ConversionException e)
+			throw new ArchiveException(e);
+	}
+	
+	protected T fromDataType (T) (DataType value)
+	{
+		try
+			return to!(T)(value);
+		
+		catch (ConversionException e)
+			throw new ArchiveException(e);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/archives/ArchiveException.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,28 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 30, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization.archives.ArchiveException;
+
+import orange.serialization.SerializationException;
+import orange.util.string;
+
+class ArchiveException : SerializationException
+{	
+	this (string message)
+	{
+		super(message);
+	}
+	
+	this (string message, string file, long line)
+	{
+		super(message, file, line);
+	}
+	
+	this (Exception exception)
+	{
+		super(exception);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/archives/XMLArchive.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,596 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization.archives.XMLArchive;
+
+version (Tango)
+{
+	import tango.text.xml.DocPrinter;
+	import tango.text.xml.Document;
+	import tango.util.Convert : to;
+}
+
+import orange.serialization.archives._;
+import orange.util._;
+
+private enum ArchiveMode
+{
+	archiving,
+	unarchiving
+}
+
+class XMLArchive (U = char) : Archive!(U)
+{
+	static assert (isChar!(U), format!(`The given type "`, U, `" is not a valid type. Valid types are: "char", "wchar" and "dchar".`));
+		
+	private struct Tags
+	{
+		static const DataType structTag = "struct";	
+		static const DataType dataTag = "data";
+		static const DataType archiveTag = "archive";
+		static const DataType arrayTag = "array";
+		static const DataType objectTag = "object";
+		static const DataType baseTag = "base";
+		static const DataType stringTag = "string";
+		static const DataType referenceTag = "reference";
+		static const DataType pointerTag = "pointer";
+		static const DataType associativeArrayTag = "associativeArray";
+		static const DataType typedefTag = "typedef";
+		static const DataType nullTag = "null";
+		static const DataType enumTag = "enum";		
+	}
+
+	private struct Attributes
+	{
+		static const DataType typeAttribute = "type";
+		static const DataType versionAttribute = "version";
+		static const DataType lengthAttribute = "length";
+		static const DataType keyAttribute = "key";
+		static const DataType runtimeTypeAttribute = "runtimeType";
+		static const DataType idAttribute = "id";
+		static const DataType keyTypeAttribute = "keyType";
+		static const DataType valueTypeAttribute = "valueType";
+	}
+	
+	private
+	{
+		DataType archiveType = "org.dsource.orange.xml";
+		DataType archiveVersion = "0.1";
+		
+		Document!(U) doc;
+		doc.Node lastElement;
+		DocPrinter!(U) printer;
+		doc.Node lastElementSaved;
+		
+		bool hasBegunArchiving;
+		bool hasBegunUnarchiving;
+		
+		DataType[void*] archivedReferences;
+		void*[DataType] unarchivedReferences;
+		
+		size_t idCounter;
+	}
+	
+	this ()
+	{
+		doc = new Document!(U);
+	}
+	
+	public void beginArchiving ()
+	{
+		if (!hasBegunArchiving)
+		{
+			doc.header;
+			lastElement = doc.tree.element(null, Tags.archiveTag)
+				.attribute(null, Attributes.typeAttribute, archiveType)
+				.attribute(null, Attributes.versionAttribute, archiveVersion);
+			lastElement = lastElement.element(null, Tags.dataTag);
+			
+			hasBegunArchiving = true;
+		}		
+	}
+	
+	public void beginUnarchiving (DataType data)
+	{
+		if (!hasBegunUnarchiving)
+		{
+			doc.parse(data);	
+			hasBegunUnarchiving = true;
+			
+			auto set = doc.query[Tags.archiveTag][Tags.dataTag];
+
+			if (set.nodes.length == 1)
+				lastElement = set.nodes[0];
+			
+			else if (set.nodes.length == 0)
+				throw new ArchiveException(errorMessage!(ArchiveMode.unarchiving) ~ `The "` ~ to!(string)(Tags.dataTag) ~ `" tag could not be found.`, __FILE__, __LINE__);
+			
+			else
+				throw new ArchiveException(errorMessage!(ArchiveMode.unarchiving) ~ `There were more than one "` ~ to!(string)(Tags.dataTag) ~ `" tag.`, __FILE__, __LINE__);
+		}
+	}
+	
+	public DataType data ()
+	{
+		if (!printer)
+			printer = new DocPrinter!(U);
+		
+		return printer.print(doc);
+	}
+	
+	public void reset ()
+	{
+		hasBegunArchiving = false;
+		hasBegunUnarchiving = false;
+		idCounter = 0;
+		doc.reset;
+	}
+	
+	private void begin ()
+	{
+		lastElementSaved = lastElement;
+	}
+	
+	private void end ()
+	{
+		lastElement = lastElementSaved;
+	}
+	
+	public void archive (T) (T value, DataType key, void delegate () dg = null)
+	{
+		if (!hasBegunArchiving)
+			beginArchiving();
+		
+		restore(lastElement) in {
+			bool callDelegate = true;
+			
+			static if (isTypeDef!(T))
+				archiveTypeDef(value, key);
+			
+			else static if (isObject!(T))
+				archiveObject(value, key, callDelegate);
+			
+			else static if (isStruct!(T))
+				archiveStruct(value, key);
+			 
+			else static if (isString!(T))
+				archiveString(value, key);
+			
+			else static if (isArray!(T))
+				archiveArray(value, key);
+			
+			else static if (isAssociativeArray!(T))
+				archiveAssociativeArray(value, key);
+			
+			else static if (isPrimitive!(T))
+				archivePrimitive(value, key);
+			
+			else static if (isPointer!(T))
+				archivePointer(value, key, callDelegate);
+			
+			else static if (isEnum!(T))
+				archiveEnum(value, key);
+			
+			else
+				static assert(false, format!(`The type "`, T, `" cannot be archived.`));
+			
+			if (callDelegate && dg)
+				dg();
+		};
+	}
+	
+	private void archiveObject (T) (T value, DataType key, ref bool callDelegate)
+	{		
+		if (!value)
+		{
+			lastElement.element(null, Tags.nullTag)
+			.attribute(null, Attributes.typeAttribute, toDataType(T.stringof))
+			.attribute(null, Attributes.keyAttribute, key);
+			callDelegate = false;
+		}
+		
+		else if (auto reference = getArchivedReference(value))
+		{
+			archiveReference(key, reference);
+			callDelegate = false;
+		}
+		
+		else
+		{
+			DataType id = nextId;
+			
+			lastElement = lastElement.element(null, Tags.objectTag)
+			.attribute(null, Attributes.runtimeTypeAttribute, toDataType(value.classinfo.name))
+			.attribute(null, Attributes.typeAttribute, toDataType(T.stringof))
+			.attribute(null, Attributes.keyAttribute, key)
+			.attribute(null, Attributes.idAttribute, id);
+			
+			addArchivedReference(value, id);
+		}
+	}
+
+	private void archiveStruct (T) (T value, DataType key)
+	{
+		lastElement = lastElement.element(null, Tags.structTag)
+		.attribute(null, Attributes.typeAttribute, toDataType(T.stringof))
+		.attribute(null, Attributes.keyAttribute, key);
+	}
+	
+	private void archiveString (T) (T value, DataType key)
+	{
+		lastElement.element(null, Tags.stringTag, toDataType(value))
+		.attribute(null, Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof))
+		.attribute(null, Attributes.keyAttribute, key);
+	}
+
+	private void archiveArray (T) (T value, DataType key)
+	{		
+		lastElement = lastElement.element(null, Tags.arrayTag)		
+		.attribute(null, Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof))
+		.attribute(null, Attributes.lengthAttribute, toDataType(value.length))
+		.attribute(null, Attributes.keyAttribute, key);
+	}
+
+	private void archiveAssociativeArray (T) (T value, DataType key)
+	{
+		lastElement = lastElement.element(null, Tags.associativeArrayTag)		
+		.attribute(null, Attributes.keyTypeAttribute, toDataType(KeyTypeOfAssociativeArray!(T).stringof))
+		.attribute(null, Attributes.valueTypeAttribute, toDataType(ValueTypeOfAssociativeArray!(T).stringof))
+		.attribute(null, Attributes.lengthAttribute, toDataType(value.length))
+		.attribute(null, Attributes.keyAttribute, key);
+	}
+
+	private void archivePointer (T) (T value, DataType key, ref bool callDelegate)
+	{
+		if (auto reference = getArchivedReference(value))
+		{
+			archiveReference(key, reference);
+			callDelegate = false;
+		}
+		
+		else
+		{
+			DataType id = nextId;
+			
+			lastElement = lastElement.element(null, Tags.pointerTag)
+			.attribute(null, Attributes.keyAttribute, key)
+			.attribute(null, Attributes.idAttribute, id);
+			
+			addArchivedReference(value, id);
+		}
+	}
+	
+	private void archiveEnum (T) (T value, DataType key)
+	{
+		lastElement.element(null, Tags.enumTag, toDataType(value))
+		.attribute(null, Attributes.typeAttribute, toDataType(T.stringof))
+		.attribute(null, Attributes.keyAttribute, key);
+	}
+
+	private void archivePrimitive (T) (T value, DataType key)
+	{
+		lastElement.element(null, toDataType(T.stringof), toDataType(value))
+		.attribute(null, Attributes.keyAttribute, key);
+	}
+	
+	private void archiveTypeDef (T) (T value, DataType key)
+	{
+		lastElement = lastElement.element(null, Tags.typedefTag)
+		.attribute(null, Attributes.typeAttribute, toDataType(BaseTypeOfTypeDef!(T).stringof));
+		.attribute(null, Attributes.key, key);
+	}
+	
+	public T unarchive (T) (DataType key, T delegate (T) dg = null)
+	{
+		if (!hasBegunUnarchiving)
+			beginUnarchiving(data);
+		
+		return restore!(T)(lastElement) in {
+			T value;
+			
+			bool callDelegate = true;
+			
+			static if (isTypeDef!(T))
+				value = unarchiveTypeDef!(T)(key);
+			
+			else static if (isObject!(T))
+				value = unarchiveObject!(T)(key, callDelegate);				
+
+			else static if (isStruct!(T))
+				value = unarchiveStruct!(T)(key);
+			
+			else static if (isString!(T))
+				value = unarchiveString!(T)(key);
+			 
+			else static if (isArray!(T))
+				value = unarchiveArray!(T)(key);
+
+			else static if (isAssociativeArray!(T))
+				value = unarchiveAssociativeArray!(T)(key);
+
+			else static if (isPrimitive!(T))
+				value = unarchivePrimitive!(T)(key);
+
+			else static if (isPointer!(T))
+				value = unarchivePointer!(T)(key, callDelegate);
+			
+			else static if (isEnum!(T))
+				value = unarchiveEnum!(T)(key);
+			
+			else
+				static assert(false, format!(`The type "`, T, `" cannot be unarchived.`));
+
+			if (callDelegate && dg)
+				return dg(value);
+			
+			return value;
+		};
+	}
+
+	private T unarchiveObject (T) (DataType key, ref bool callDelegate)
+	{			
+		DataType id = unarchiveReference(key);
+		
+		if (auto reference = getUnarchivedReference!(T)(id))
+		{
+			callDelegate = false;
+			return *reference;
+		}
+		
+		auto tmp = getElement(Tags.objectTag, key, Attributes.keyAttribute, false);
+		
+		if (!tmp)
+		{
+			lastElement = getElement(Tags.nullTag, key);
+			callDelegate = false;
+			return null;
+		}
+		
+		lastElement = tmp;
+		
+		auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute);
+		auto name = fromDataType!(string)(runtimeType);
+		id = getValueOfAttribute(Attributes.idAttribute);
+				
+		T result;
+		
+		static if (is(typeof(T._ctor)))
+		{
+			ParameterTupleOf!(typeof(T._ctor)) params;			
+			result = factory!(T, typeof(params))(name, params);
+		}
+		
+		else
+			 result = factory!(T)(name);
+		
+		addUnarchivedReference(result, id);
+		
+		return result;
+	}
+
+	private T unarchiveStruct (T) (DataType key)
+	{
+		lastElement = getElement(Tags.structTag, key);
+		
+		return T.init;
+	}
+	
+	private T unarchiveString (T) (DataType key)
+	{
+		return fromDataType!(T)(getElement(Tags.stringTag, key).value);
+	}
+
+	private T unarchiveArray (T) (DataType key)
+	{			
+		T value;
+		
+		lastElement = getElement(Tags.arrayTag, key);
+		auto length = getValueOfAttribute(Attributes.lengthAttribute);
+		value.length = fromDataType!(size_t)(length);
+		
+		return value;
+	}
+
+	private T unarchiveAssociativeArray (T) (DataType key)
+	{		
+		lastElement = getElement(Tags.associativeArrayTag, key);
+		
+		return T.init;
+	}
+
+	private T unarchivePointer (T) (DataType key, ref bool callDelegate)
+	{
+		DataType id = unarchiveReference(key);
+		
+		if (auto reference = getUnarchivedReference!(T)(id))
+		{
+			callDelegate = false;
+			return *reference;
+		}
+
+		lastElement = getElement(Tags.pointerTag, key);
+		id = getValueOfAttribute(Attributes.idAttribute);
+				
+		T result = new BaseTypeOfPointer!(T);
+		
+		addUnarchivedReference(result, id);
+		
+		return result;
+	}
+	
+	private T unarchiveEnum (T) (DataType key)
+	{
+		return fromDataType!(T)(getElement(Tags.enumTag, key).value);
+	}
+
+	private T unarchivePrimitive (T) (DataType key)
+	{		
+		return fromDataType!(T)(getElement(toDataType(T.stringof), key).value);
+	}
+	
+	private T unarchiveTypeDef (T) (DataType key)
+	{
+		lastElement = getElement(Tags.typedefTag, key);
+		
+		return T.init;
+	}
+	
+	public AssociativeArrayVisitor!(KeyTypeOfAssociativeArray!(T), ValueTypeOfAssociativeArray!(T)) unarchiveAssociativeArrayVisitor (T)  ()
+	{
+		return AssociativeArrayVisitor!(KeyTypeOfAssociativeArray!(T), ValueTypeOfAssociativeArray!(T))(this);
+	}
+	
+	public void archiveBaseClass (T : Object) (DataType key)
+	{
+		lastElement = lastElement.element(null, Tags.baseTag)
+		.attribute(null, Attributes.typeAttribute, toDataType(T.stringof))
+		.attribute(null, Attributes.keyAttribute, key);
+	}
+	
+	public void unarchiveBaseClass (T : Object) (DataType key)
+	{
+		lastElement = getElement(Tags.baseTag, key);
+	}
+	
+	template errorMessage (ArchiveMode mode = ArchiveMode.archiving)
+	{
+		static if (mode == ArchiveMode.archiving)
+			const errorMessage = "Could not continue archiving due to unrecognized data format: ";
+			
+		else static if (mode == ArchiveMode.unarchiving)
+			const errorMessage = "Could not continue unarchiving due to unrecognized data format: ";
+	}
+	
+	private doc.Node getElement (DataType tag, DataType key, DataType attribute = Attributes.keyAttribute, bool throwOnError = true)
+	{
+		auto set = lastElement.query[tag].attribute((doc.Node node) {			
+			if (node.name == attribute && node.value == key)
+				return true;
+			
+			return false;
+		});
+		
+		if (set.nodes.length == 1)
+			return set.nodes[0].parent;
+		
+		else
+		{
+			if (throwOnError)
+			{
+				if (set.nodes.length == 0)
+					throw new ArchiveException(`Could not find an element "` ~ to!(string)(tag) ~ `" with the attribute "` ~ to!(string)(Attributes.keyAttribute) ~ `" with the value "` ~ to!(string)(key) ~ `".`, __FILE__, __LINE__);
+				
+				else
+					throw new ArchiveException(`Could not unarchive the value with the key "` ~ to!(string)(key) ~ `" due to malformed data.`, __FILE__, __LINE__);
+			}
+			
+			return null;
+		}		
+	}
+	
+	private DataType getValueOfAttribute (DataType attribute)
+	{
+		auto set = lastElement.query.attribute(attribute);
+		
+		if (set.nodes.length == 1)
+			return set.nodes[0].value;
+		
+		else if (set.nodes.length == 0)
+			throw new ArchiveException(`Could not find the attribute "` ~ to!(string)(attribute) ~ `".`, __FILE__, __LINE__);
+		
+		else
+			throw new ArchiveException(`Could not unarchive the value of the attribute "` ~ to!(string)(attribute) ~ `" due to malformed data.`, __FILE__, __LINE__);
+	}
+	
+	private void addArchivedReference (T) (T value, DataType id)
+	{
+		static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`));
+		
+		archivedReferences[cast(void*) value] = id;
+	}
+	
+	private void addUnarchivedReference (T) (T value, DataType id)
+	{
+		static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`));
+		
+		unarchivedReferences[id] = cast(void*) value;
+	}
+	
+	private DataType getArchivedReference (T) (T value)
+	{
+		if (auto tmp = cast(void*) value in archivedReferences)
+			return *tmp;
+		
+		return null;
+	}
+	
+	private T* getUnarchivedReference (T) (DataType id)
+	{
+		if (auto reference = id in unarchivedReferences)
+			return cast(T*) reference;
+		
+		return null;
+	}
+	
+	private DataType nextId ()
+	{
+		return toDataType(idCounter++);
+	}
+	
+	private void archiveReference (DataType key, DataType id)
+	{		
+		lastElement.element(null, Tags.referenceTag, id)
+		.attribute(null, Attributes.keyAttribute, key);
+	}
+	
+	private DataType unarchiveReference (DataType key)
+	{	
+		auto element = getElement(Tags.referenceTag, key, Attributes.keyAttribute, false);
+		
+		if (element)
+			return element.value;
+		
+		return cast(DataType) null;
+	}
+	
+	private struct AssociativeArrayVisitor(Key, Value)
+	{
+		private XMLArchive archive;
+		
+		static AssociativeArrayVisitor opCall (XMLArchive archive)
+		{
+			AssociativeArrayVisitor aai;
+			aai.archive = archive;
+			
+			return aai;
+		}
+		
+		int opApply(int delegate(ref Key, ref Value) dg)
+		{  
+			int result;
+			
+			foreach (node ; archive.lastElement.children)
+			{
+				restore(archive.lastElement) in {
+					archive.lastElement = node;
+					
+					if (node.attributes.exist)
+					{
+						Key key = to!(Key)(archive.getValueOfAttribute(Attributes.keyAttribute));
+						Value value = to!(Value)(node.value);
+						
+						result = dg(key, value);	
+					}		
+				};
+				
+				if (result)
+					break;
+			}
+			
+			return result;
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/serialization/archives/_.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,13 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.serialization.archives._;
+
+public:
+
+import orange.serialization.archives.Archive;
+import orange.serialization.archives.ArchiveException;
+import orange.serialization.archives.XMLArchive;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/util/CTFE.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,9 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.util.CTFE;
+
+public import mambo.util.CTFE;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/util/Reflection.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,9 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.util.Reflection;
+
+public import mambo.util.Reflection;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/util/Traits.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,46 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.util.Traits;
+
+public import mambo.util.Traits;
+
+import orange.serialization.Serializable;
+import orange.serialization.archives.Archive;
+import orange.util._;
+
+template isArchive (T)
+{
+	const isArchive = is(typeof({
+		alias T.DataType Foo;
+	})) &&
+
+	is(typeof(T.archive(0, TypeOfDataType!(T).init, {}))) &&
+	is(typeof(T.unarchive!(int))) && 
+	is(typeof(T.beginArchiving)) &&
+	is(typeof(T.beginUnarchiving(TypeOfDataType!(T).init))) &&
+	is(typeof(T.archiveBaseClass!(Object))) &&
+	is(typeof(T.unarchiveBaseClass!(Object))) &&
+	is(typeof(T.reset)) &&
+	is(typeof({TypeOfDataType!(T) a = T.data;})) &&
+	is(typeof(T.unarchiveAssociativeArrayVisitor!(int[string])));
+	
+}
+
+template isSerializable (T, ArchiveType)
+{
+	const isSerializable = is(typeof(T.toData(ArchiveType.init, ArchiveType.DataType.init))) && is(typeof(T.fromData(ArchiveType.init, ArchiveType.DataType.init)));
+}
+
+template isISerializable (T)
+{
+	const isISerializable = is(T : ISerializable);
+}
+
+template TypeOfDataType (T)
+{
+	alias T.DataType TypeOfDataType;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/util/Use.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,90 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 29, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.util.Use;
+
+import mambo.io;
+
+version (Tango)
+{
+	import tango.core.Tuple;
+	import tango.core.Traits;
+}
+
+else
+{
+	import std.typetuple;
+	import std.traits;
+	
+	alias ReturnType ReturnTypeOf;
+	alias ParameterTypeTuple ParameterTupleOf;
+}
+
+struct OpInStruct (ARGS...)
+{
+	static assert (ARGS.length > 0);
+	
+	private
+	{
+		alias ReturnTypeOf!(ARGS[0]) ReturnType;
+		
+		static if (ARGS.length >= 2)
+			alias Tuple!(ReturnType delegate (ARGS), ARGS[1 .. $]) NEW_ARGS;
+			
+		else
+			alias Tuple!(ReturnType delegate (ARGS)) NEW_ARGS;
+	}
+		
+	NEW_ARGS args;
+	
+	ReturnType opIn (ARGS[0] dg)
+	{
+		assert(args[0]);
+		
+		static if (NEW_ARGS.length == 1)
+			return args[0](dg);
+			
+		else
+			return args[0](dg, args[1 .. $]);
+	}
+}
+
+struct RestoreStruct (U, T)
+{
+	U delegate(U delegate (), ref T) dg; 
+	T* value;
+	
+	U opIn (U delegate () deleg)
+	{
+		return dg(deleg, *value);
+	}
+}
+RestoreStruct!(U, T) restore (U = void, T) (ref T val)
+{
+	RestoreStruct!(U, T) restoreStruct;
+	
+	restoreStruct.dg = (U delegate () dg, ref T value){
+		T t = value;
+		
+		static if (is(U == void))
+		{
+			dg();
+			value = t;
+		}
+		
+		else
+		{
+			auto result = dg();
+			value = t;
+			
+			return result;
+		}
+	};
+	
+	restoreStruct.value = &val;
+	
+	return restoreStruct;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/util/_.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,16 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.util._;
+
+public:
+
+import orange.util.CTFE;
+import orange.util.io;
+import orange.util.Reflection;
+import orange.util.string;
+import orange.util.Traits;
+import orange.util.Use;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/util/io.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,3 @@
+module orange.util.io;
+
+public import mambo.io;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/util/string.d	Wed May 26 17:19:13 2010 +0200
@@ -0,0 +1,9 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Jan 26, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.util.string;
+
+public import mambo.string;
\ No newline at end of file