changeset 37:90f6a44b9475

Merged "experimental" into "default".
author Jacob Carlborg <doob@me.com>
date Wed, 03 Aug 2011 21:58:21 +0200
parents 947c32ec0ea7 (current diff) c523d436052f (diff)
children 9443bcddc699
files orange/_.d orange/util/io.d orange/util/string.d
diffstat 28 files changed, 4106 insertions(+), 1832 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Oct 04 20:45:32 2010 +0200
+++ b/.hgignore	Wed Aug 03 21:58:21 2011 +0200
@@ -12,8 +12,9 @@
 *.dylib
 main.d
 main
-main.d.deps
+*.deps
 *.framework
 kandil
 lib
-import
\ No newline at end of file
+import
+unittest
\ No newline at end of file
--- a/Makefile	Mon Oct 04 20:45:32 2010 +0200
+++ b/Makefile	Wed Aug 03 21:58:21 2011 +0200
@@ -1,6 +1,8 @@
 LIBNAME		=	orange
 SRC			=	\
-	_.d \
+	core/io.d \
+	core/string.d \
+	core/_.d \
 	serialization/Events.d \
 	serialization/RegisterWrapper.d \
 	serialization/Serializable.d \
@@ -16,17 +18,20 @@
 	util/Traits.d \
 	util/Use.d \
 	util/_.d \
-	util/io.d \
-	util/string.d \
 	util/collection/Array.d \
+	util/collection/_.d \
 	xml/PhobosXML.d \
 	xml/XMLDocument.d \
-	_.d
+	xml/_.d \
 
 DC			=	dmd
 DCFLAGS		=	-I/usr/include/d -I/usr/local/include/d
 
 
+UNITTEST = test/UnitTester.d \
+	tests/Serializer.d \
+	tests/all.d \
+
 # Everything below this line should be fairly generic (with a few hard-coded things).
 
 OBJ         =   $(addsuffix .o,$(addprefix $(LIBNAME)/,$(basename $(SRC))))
@@ -60,4 +65,4 @@
 
 %.o : %.d
 	@echo Compiling $< . . .
-	@$(DC) -c $(DCFLAGS) $< -of$@ -Hfimport/$(basename $@).di
+	@$(DC) -c $< -of$@ -Hfimport/$(basename $@).di
--- a/dsss.conf	Mon Oct 04 20:45:32 2010 +0200
+++ b/dsss.conf	Wed Aug 03 21:58:21 2011 +0200
@@ -1,1 +1,8 @@
-[orange]
\ No newline at end of file
+version (unittest) {
+	[tests/all.d]
+	buildflags += -unittest
+	target = unittest
+	version += OrangeUnitTest
+} else {
+	[orange]
+}
\ No newline at end of file
--- a/orange/_.d	Mon Oct 04 20:45:32 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/**
- * 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/core/_.d	Wed Aug 03 21:58:21 2011 +0200
@@ -0,0 +1,12 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Oct 17, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.core._;
+
+public:
+
+import orange.core.io;
+import orange.core.string;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/core/io.d	Wed Aug 03 21:58:21 2011 +0200
@@ -0,0 +1,66 @@
+/**
+ * Copyright: Copyright (c) 2007-2008 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: 2007
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ * 
+ */
+module orange.core.io;
+
+version (Tango)
+{
+	import tango.io.Stdout;
+	import tango.io.Console;
+	
+	import orange.core.string;
+}
+
+else 
+	import std.stdio;
+
+/**
+ * Print to the standard output
+ * 
+ * Params:
+ *     args = what to print
+ */
+void print (A...)(A args)
+{
+	version (Tango)
+	{
+		const string fmt = "{}{}{}{}{}{}{}{}"
+					        "{}{}{}{}{}{}{}{}"
+					        "{}{}{}{}{}{}{}{}";
+				
+		static assert (A.length <= fmt.length / 2, "mambo.io.print :: too many arguments");
+		
+		Stdout.format(fmt[0 .. args.length * 2], args).flush;
+	}
+		
+	
+	else
+		write(args);
+}
+
+/**
+ * Print to the standard output, adds a new line
+ * 
+ * Params:
+ *     args = what to print
+ */
+void println (A...)(A args)
+{
+	version (Tango)
+	{
+		const string fmt = "{}{}{}{}{}{}{}{}"
+					        "{}{}{}{}{}{}{}{}"
+					        "{}{}{}{}{}{}{}{}";
+
+		static assert (A.length <= fmt.length / 2, "mambo.io.println :: too many arguments");
+		
+		Stdout.formatln(fmt[0 .. args.length * 2], args);
+	}
+
+	else
+		writeln(args);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/core/string.d	Wed Aug 03 21:58:21 2011 +0200
@@ -0,0 +1,952 @@
+/**
+ * Copyright: Copyright (c) 2008-2009 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: 2008
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ * 
+ */
+module orange.core.string;
+
+public import orange.util.collection.Array;
+
+version (Tango)
+{
+	static import tango.stdc.stringz;
+	import tango.text.Unicode : toFold, isDigit;
+	import tango.text.convert.Utf;
+	import tango.text.Util;
+	
+	alias tango.stdc.stringz.toStringz toStringz;
+	alias tango.stdc.stringz.toString16z toString16z;
+	alias tango.stdc.stringz.toString32z toString32z;
+	
+	alias tango.stdc.stringz.fromStringz fromStringz;
+	alias tango.stdc.stringz.fromString16z fromString16z;
+	alias tango.stdc.stringz.fromString32z fromString32z;
+	
+	alias tango.text.convert.Utf.toString16 toString16;
+	alias tango.text.convert.Utf.toString32 toString32;
+}
+
+else
+{	
+	import std.string;
+	import std.utf;
+	static import std.ascii;
+	static import std.conv;
+	static import std.array;
+	
+	version = Phobos;
+	
+	private alias std.string.toLower toFold;
+	
+	alias std.utf.toUTF8 toString;
+	alias std.utf.toUTF16 toString16;
+	alias std.utf.toUTF32 toString32;
+	
+	alias std.string.toStringz toStringz;
+	alias std.utf.toUTF16z toString16z;
+	
+	alias std.ascii.isHexDigit isHexDigit;
+}
+
+import orange.util.Traits;
+
+version (Tango)
+{
+	/**
+	 * string alias
+	 */
+	alias char[] string;
+
+	/**
+	 * wstring alias
+	 */
+	alias wchar[] wstring;
+
+	/**
+	 * dstring alias
+	 */
+	alias dchar[] dstring;
+}
+
+/**
+ * Compares the $(D_PSYMBOL string) to another $(D_PSYMBOL string), ignoring case
+ * considerations.  Two strings are considered equal ignoring case if they are of the
+ * same length and corresponding characters in the two strings  are equal ignoring case.
+ * 
+ * Params:
+ *     str = The $(D_PSYMBOL string) first string to compare to
+ *     anotherString = The $(D_PSYMBOL string) to compare the first $(D_PSYMBOL string) with
+ *     
+ * Returns: $(D_KEYWORD true) if the arguments is not $(D_KEYWORD null) and it
+ *          represents an equivalent $(D_PSYMBOL string) ignoring case; $(D_KEYWORD false) otherwise
+ *          
+ * Throws: AssertException if the length of any of the strings is 0
+ *          
+ * See_Also: opEquals(Object)
+ */
+bool equalsIgnoreCase (string str, string anotherString)
+in
+{
+	assert(str.length > 0, "mambo.string.equalsIgnoreCase: The length of the first string was 0");
+	assert(anotherString.length > 0, "mambo.string.equalsIgnoreCase: The length of the second string was 0");
+}
+body
+{	
+	if (str == anotherString)
+		return true;
+
+	return toFold(str) == toFold(anotherString);
+}
+
+/**
+ * Compares the $(D_PSYMBOL wstring) to another $(D_PSYMBOL wstring), ignoring case
+ * considerations. Two wstrings are considered equal ignoring case if they are of the
+ * same length and corresponding characters in the two wstrings are equal ignoring case.
+ * 
+ * Params:
+ *     str = The $(D_PSYMBOL wstring) first string to compre to
+ *     anotherString = The $(D_PSYMBOL wstring) to compare the first $(D_PSYMBOL wstring) against
+ *     
+ * Returns: $(D_KEYWORD true) if the argument is not $(D_KEYWORD null) and it
+ *          represents an equivalent $(D_PSYMBOL wstring) ignoring case; (D_KEYWORD
+ *          false) otherwise
+ *          
+ * Throws: AssertException if the length of any of the wstrings is 0
+ *          
+ * See_Also: opEquals(Object)
+ */
+bool equalsIgnoreCase (wstring str, wstring anotherString)
+in
+{
+	assert(str.length > 0, "mambo.string.equalsIgnoreCase: The length of the first string was 0");
+	assert(anotherString.length > 0, "mambo.string.equalsIgnoreCase: The length of the second string was 0");
+}
+body
+{
+	if (str == anotherString)
+		return true;
+
+	version (Tango)
+		return toFold(str) == toFold(anotherString);
+
+	else
+		return toFold(toUTF8(str)) == toFold(toUTF8(anotherString));
+}
+
+/**
+ * Compares the $(D_PSYMBOL dstring) to another $(D_PSYMBOL dstring), ignoring case
+ * considerations. Two wstrings are considered equal ignoring case if they are of the
+ * same length and corresponding characters in the two wstrings are equal ignoring case.
+ * 
+ * Params:
+ *     str = The $(D_PSYMBOL dstring) first string to compare to
+ *     anotherString = The $(D_PSYMBOL wstring) to compare the first $(D_PSYMBOL dstring) against
+ *     
+ * Returns: $(D_KEYWORD true) if the argument is not $(D_KEYWORD null) and it
+ *          represents an equivalent $(D_PSYMBOL dstring) ignoring case; $(D_KEYWORD false) otherwise
+ *          
+ * Throws: AssertException if the length of any of the dstrings are 0
+ *          
+ * See_Also: opEquals(Object)
+ */
+bool equalsIgnoreCase (dstring str, dstring anotherString)
+in
+{
+	assert(str.length > 0, "mambo.string.equalsIgnoreCase: The length of the first string was 0");
+	assert(anotherString.length > 0, "mambo.string.equalsIgnoreCase: The length of the second string was 0");
+}
+body
+{
+	if (str == anotherString)
+		return true;
+
+	version (Tango)
+		return toFold(str) == toFold(anotherString);
+
+	else
+		return toFold(toUTF8(str)) == toFold(toUTF8(anotherString));
+}
+
+/**
+ * Returns the char value at the specified index. An index ranges from 0 to length - 1.
+ * The first $(D_KEYWORD char) value of the sequence is at index 0, the next at index 1,
+ * and so on, as for array indexing.
+ * 
+ * Params:
+ * 	   str = the string to get the $(D_KEYWORD char) from
+ *     index = the index of the $(D_KEYWORD char) value.
+ *     
+ * Returns: the $(D_KEYWORD char) value at the specified index of the string.
+ *          The first $(D_KEYWORD char) value is at index 0.
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_CODE index) argument is
+ *         not less than the length of the string.
+ */
+char charAt (string str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.charAt: The length of the string was 0");
+	assert(index <= str.length, "mambo.string.charAt: The index was to greater than the length of the string");
+}
+body
+{
+	return str[index];
+}
+
+/**
+ * Returns the $(D_KEYWORD char) value at the specified index. An index ranges from 0 to
+ * length - 1. The first $(D_KEYWORD char) value of the sequence is at index 0, the next
+ * at index 1, and so on, as for array indexing.
+ * 
+ * Params:
+ * 	   str = the wstring to get the $(D_KEYWORD char) from
+ *     index = the index of the $(D_KEYWORD char) value.
+ *     
+ * Returns: the $(D_KEYWORD char) value at the specified index of the wstring.
+ *          The first $(D_KEYWORD char) value is at index 0.
+ * 
+ * Throws: AssertException if the length of the wstring is 0
+ * Throws: AssertException if the $(D_CODE index) argument is
+ *         not less than the length of the wstring.
+ */
+wchar charAt (wstring str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.charAt: The length of the string was 0");
+	assert(index <= str.length, "mambo.string.charAt: The index was to greater than the length of the string");
+}
+body
+{
+	return str[index];
+}
+
+/**
+ * Returns the $(D_KEYWORD char) value at the specified index. An index ranges from 0 to
+ * length - 1. The first $(D_KEYWORD char) value of the sequence is at index 0, the next
+ * at index 1, and so on, as for array indexing.
+ * 
+ * Params:
+ * 	   str = the dstring to get the $(D_KEYWORD char) from
+ *     index = the index of the $(D_KEYWORD char) value.
+ *     
+ * Returns: the $(D_KEYWORD char) value at the specified index of the dstring.
+ *          The first $(D_KEYWORD char) value is at index 0.
+ * 
+ * Throws: AssertException if the length of the dstring is 0
+ * Throws: AssertException if the $(D_CODE index) argument is
+ *         not less than the length of the dstring.
+ */
+dchar charAt (dstring str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.charAt: The length of the string was 0");
+	assert(index <= str.length, "mambo.string.charAt: The index was to greater than the length of the string");
+}
+body
+{
+	return str[index];
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * at the specified $(D_PARAM beginIndex) and extends to the character at index
+ * $(D_PARAM endIndex) - 1. Thus the length of the substring is $(D_PARAM endIndex - beginIndex).
+ * 
+ * Examples:
+ * ---
+ * "hamburger".substring(4, 8) returns "urge"
+ * "smiles".substring(1, 5) returns "mile"
+ * ---
+ * 
+ * Params:
+ * 	   str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive.
+ *     endIndex = the ending index, exclusive.
+ *     
+ * Returns: the specified substring.
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than $(D_PARAM endIndex).
+ * Throws: AssertException if $(D_PARAM endIndex) is larger than the 
+ *  	   length of the $(D_PSYMBOL string).
+ */
+string substring (string str, size_t beginIndex, size_t endIndex)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(beginIndex < endIndex, "mambo.string.substring: The first index was greater the second");
+	assert(endIndex <= str.length, "mambo.string.substring: The second index was greater then the length of the string");
+}
+body
+{
+	version (Tango) return str[beginIndex .. endIndex].dup;
+	else return str[beginIndex .. endIndex].idup;
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * at the specified $(D_PARAM beginIndex) and extends to the character at index
+ * $(D_PARAM endIndex) - 1. Thus the length of the substring is $(D_PARAM endIndex - beginIndex).
+ * 
+ * Examples:
+ * ---
+ * "hamburger".substring(4, 8) returns "urge"
+ * "smiles".substring(1, 5) returns "mile"
+ * ---
+ * 
+ * Params:
+ * 	   str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive.
+ *     endIndex = the ending index, exclusive.
+ *     
+ * Returns: the specified substring.
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than $(D_PARAM endIndex).
+ * Throws: AssertException if $(D_PARAM endIndex) is larger than the 
+ *  	   length of the $(D_PSYMBOL string).
+ */
+wstring substring (wstring str, size_t beginIndex, size_t endIndex)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(beginIndex < endIndex, "mambo.string.substring: The first index was greater the second");
+	assert(endIndex <= str.length, "mambo.string.substring: The second index was greater then the length of the string");
+}
+body
+{
+	version (Tango) return str[beginIndex .. endIndex].dup;
+	else return str[beginIndex .. endIndex].idup;
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * at the specified $(D_PARAM beginIndex) and extends to the character at index
+ * $(D_PARAM endIndex) - 1. Thus the length of the substring is $(D_PARAM endIndex - beginIndex).
+ * 
+ * Examples:
+ * ---
+ * "hamburger".substring(4, 8) returns "urge"
+ * "smiles".substring(1, 5) returns "mile"
+ * ---
+ * 
+ * Params:
+ * 	   str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive.
+ *     endIndex = the ending index, exclusive.
+ *     
+ * Returns: the specified substring.
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than $(D_PARAM endIndex).
+ * Throws: AssertException if $(D_PARAM endIndex) is larger than the 
+ *  	   length of the $(D_PSYMBOL string).
+ */
+dstring substring (dstring str, size_t beginIndex, size_t endIndex)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(beginIndex < endIndex, "mambo.string.substring: The first index was greater the second");
+	assert(endIndex <= str.length, "mambo.string.substring: The second index was greater then the length of the string");
+}
+body
+{
+	version (Tango) return str[beginIndex .. endIndex].dup;
+	else return str[beginIndex .. endIndex].idup;
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * with the character at the specified index and extends to the end of the string. 
+ * 
+ * Examples:
+ * ---
+ * "unhappy".substring(2) returns "happy"
+ * "Harbison".substring(3) returns "bison"
+ * "emptiness".substring(9) returns "" (an empty string)
+ * ---
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive
+ *     
+ * Returns: the specified substring
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than the length of the string.
+ */
+string substring (string str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(index < str.length, "mambo.string.substring: The index was greater than the length of the string");
+}
+body
+{
+	return str.substring(index, str.length);
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * with the character at the specified index and extends to the end of the string. 
+ * 
+ * Examples:
+ * ---
+ * "unhappy".substring(2) returns "happy"
+ * "Harbison".substring(3) returns "bison"
+ * "emptiness".substring(9) returns "" (an empty string)
+ * ---
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive
+ *     
+ * Returns: the specified substring
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than the length of the string.
+ */
+wstring substring (wstring str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(index < str.length, "mambo.string.substring: The index was greater than the length of the string");
+}
+body
+{
+	return str.substring(index, str.length);
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * with the character at the specified index and extends to the end of the string. 
+ * 
+ * Examples:
+ * ---
+ * "unhappy".substring(2) returns "happy"
+ * "Harbison".substring(3) returns "bison"
+ * "emptiness".substring(9) returns "" (an empty string)
+ * ---
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive
+ *     
+ * Returns: the specified substring
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than the length of the string.
+ */
+dstring substring (dstring str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(index < str.length, "mambo.string.substring: The index was greater than the length of the string");
+}
+body
+{
+	return str.substring(index, str.length);
+}
+
+/**
+ * Returns a new string that is a substring of the given string.
+ * 
+ * This substring is the character sequence that starts at character
+ * position pos and has a length of n characters.
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     pos = position of a character in the current string to be used 
+ *     		 as starting character for the substring.
+ *     n = Length of the substring. If this value would make the 
+ *     	   substring to span past the end of the current string content,
+ *     	   only those characters until the end of the string are used. 
+ *     	   size_t.max is the greatest possible value for an element of
+ *     	   type size_t, therefore, when this value is used, all the
+ *     	   characters between pos and the end of the string are used as
+ *     	   the initialization substring.
+ *     
+ * Returns: a string containing a substring of the given string
+ * 
+ * Throws: AssertException if pos is greater than the length of the string
+ */
+string substr (string str, size_t pos = 0, size_t n = size_t.max)
+in
+{
+	assert(pos < str.length, "mambo.string.substr: The given position was greater than the length of the string.");
+}
+body
+{
+	size_t end;
+	
+	if (n == size_t.max)
+		end = str.length;
+	
+	else
+	{
+		end = pos + n;
+		
+		if (end > str.length)
+			end = str.length;
+	}
+	
+	version (Tango) return str[pos .. end].dup;
+	else return str[pos .. end].idup;
+}
+
+/**
+ * Returns a new string that is a substring of the given string.
+ * 
+ * This substring is the character sequence that starts at character
+ * position pos and has a length of n characters.
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     pos = position of a character in the current string to be used 
+ *     		 as starting character for the substring.
+ *     n = Length of the substring. If this value would make the 
+ *     	   substring to span past the end of the current string content,
+ *     	   only those characters until the end of the string are used. 
+ *     	   size_t.max is the greatest possible value for an element of
+ *     	   type size_t, therefore, when this value is used, all the
+ *     	   characters between pos and the end of the string are used as
+ *     	   the initialization substring.
+ *     
+ * Returns: a string containing a substring of the given string
+ * 
+ * Throws: AssertException if pos is greater than the length of the string
+ */
+wstring substr (wstring str, size_t pos = 0, size_t n = size_t.max)
+in
+{
+	assert(pos < str.length, "mambo.string.substr: The given position was greater than the length of the string.");
+}
+body
+{
+	size_t end;
+	
+	if (n == size_t.max)
+		end = str.length;
+	
+	else
+	{
+		end = pos + n;
+		
+		if (end > str.length)
+			end = str.length;
+	}
+	
+	version (Tango) return str[pos .. end].dup;
+	else return str[pos .. end].idup;
+}
+
+/**
+ * Returns a new string that is a substring of the given string.
+ * 
+ * This substring is the character sequence that starts at character
+ * position pos and has a length of n characters.
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     pos = position of a character in the current string to be used 
+ *     		 as starting character for the substring.
+ *     n = Length of the substring. If this value would make the 
+ *     	   substring to span past the end of the current string content,
+ *     	   only those characters until the end of the string are used. 
+ *     	   size_t.max is the greatest possible value for an element of
+ *     	   type size_t, therefore, when this value is used, all the
+ *     	   characters between pos and the end of the string are used as
+ *     	   the initialization substring.
+ *     
+ * Returns: a string containing a substring of the given string
+ * 
+ * Throws: AssertException if pos is greater than the length of the string
+ */
+dstring substr (dstring str, size_t pos = 0, size_t n = size_t.max)
+in
+{
+	assert(pos < str.length, "mambo.string.substr: The given position was greater than the length of the string.");
+}
+body
+{
+	size_t end;
+	
+	if (n == size_t.max)
+		end = str.length;
+	
+	else
+	{
+		end = pos + n;
+		
+		if (end > str.length)
+			end = str.length;
+	}
+	
+	version (Tango) return str[pos .. end].dup;
+	else return str[pos .. end].idup;
+}
+
+/**
+ * Finds the first occurence of sub in str
+ * 
+ * Params:
+ *     str = the string to find in
+ *     sub = the substring to find
+ *     start = where to start finding
+ *     
+ * Returns: the index of the substring or size_t.max when nothing was found
+ */
+size_t find (string str, string sub)
+{
+	version (Tango)
+	{
+		size_t index = str.locatePattern(sub);
+		
+		if (index == str.length)
+			return size_t.max;
+		
+		return index;
+	}
+	
+	else
+		return std.string.indexOf(str, sub);
+	
+}
+
+/**
+ * Finds the first occurence of sub in str
+ * 
+ * Params:
+ *     str = the string to find in
+ *     sub = the substring to find
+ *     start = where to start finding
+ *     
+ * Returns: the index of the substring or size_t.max when nothing was found
+ */
+size_t find (wstring str, wstring sub)
+{
+	version (Tango)
+	{
+		size_t index = str.locatePattern(sub);
+		
+		if (index == str.length)
+			return size_t.max;
+		
+		return index;
+	}
+	
+	else
+		return std.string.indexOf(str, sub);
+}
+
+/**
+ * Finds the first occurence of sub in str
+ * 
+ * Params:
+ *     str = the string to find in
+ *     sub = the substring to find
+ *     start = where to start finding
+ *     
+ * Returns: the index of the substring or size_t.max when nothing was found
+ */
+size_t find (dstring str, dstring sub)
+{
+	version (Tango)
+	{
+		size_t index = str.locatePattern(sub);
+		
+		if (index == str.length)
+			return size_t.max;
+		
+		return index;
+	}
+	
+	else
+		return std.string.indexOf(str, sub);
+}
+
+/**
+ * Compares to strings, ignoring case differences. Returns 0 if the content
+ * matches, less than zero if a is "less" than b, or greater than zero
+ * where a is "bigger".
+ * 
+ * Params:
+ *     a = the first array 
+ *     b = the second array
+ *     end = the index where the comparision will end
+ *     
+ * Returns: Returns 0 if the content matches, less than zero if a is 
+ * 			"less" than b, or greater than zero where a is "bigger".
+ * 
+ * See_Also: mambo.collection.array.compare
+ */
+int compareIgnoreCase (U = size_t) (string a, string b, U end = U.max)
+{
+	return a.toFold().compare(b.toFold(), end);
+}
+
+/**
+ * Compares to strings, ignoring case differences. Returns 0 if the content
+ * matches, less than zero if a is "less" than b, or greater than zero
+ * where a is "bigger".
+ * 
+ * Params:
+ *     a = the first array 
+ *     b = the second array
+ *     end = the index where the comparision will end
+ *     
+ * Returns: Returns 0 if the content matches, less than zero if a is 
+ * 			"less" than b, or greater than zero where a is "bigger".
+ * 
+ * See_Also: mambo.collection.array.compare
+ */
+int compareIgnoreCase (U = size_t) (wstring a, wstring b, U end = U.max)
+{
+	return a.toFold().compare(b.toFold(), end);
+}
+
+/**
+ * Compares to strings, ignoring case differences. Returns 0 if the content
+ * matches, less than zero if a is "less" than b, or greater than zero
+ * where a is "bigger".
+ * 
+ * Params:
+ *     a = the first array 
+ *     b = the second array
+ *     end = the index where the comparision will end
+ *     
+ * Returns: Returns 0 if the content matches, less than zero if a is 
+ * 			"less" than b, or greater than zero where a is "bigger".
+ * 
+ * See_Also: mambo.collection.array.compare
+ */
+int compareIgnoreCase (U = size_t) (dstring a, dstring b, U end = U.max)
+{
+	return a.toFold().compare(b.toFold(), end);
+}
+
+/**
+ * Compares to strings, ignoring case differences. Returns 0 if the content
+ * matches, less than zero if a is "less" than b, or greater than zero
+ * where a is "bigger".
+ * 
+ * Params:
+ *     a = the first array 
+ *     b = the second array
+ *     end = the index where the comparision will end
+ *     
+ * Returns: Returns 0 if the content matches, less than zero if a is 
+ * 			"less" than b, or greater than zero where a is "bigger".
+ * 
+ * See_Also: mambo.string.compareIgnoreCase
+ */
+alias compareIgnoreCase icompare;
+
+/**
+ * Checks if the given character is a hexdecimal digit character.
+ * Hexadecimal digits are any of: 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
+ * 
+ * Params:
+ *     ch = the character to be checked
+ *     
+ * Returns: true if the given character is a hexdecimal digit character otherwise false
+ */
+version (Tango)
+{
+	bool isHexDigit (dchar ch)
+	{
+
+		switch (ch)
+		{
+			case 'A': return true;				
+			case 'B': return true;
+			case 'C': return true;
+			case 'D': return true;
+			case 'E': return true;
+			case 'F': return true;
+	
+			case 'a': return true;
+			case 'b': return true;
+			case 'c': return true;
+			case 'd': return true;
+			case 'e': return true;
+			case 'f': return true;
+	
+			default: break;
+		}
+
+		if (isDigit(ch))
+			return true;
+	
+		return false;
+	}
+}
+
+/*version (Tango)
+{
+	string toString (string str)
+	{
+		return str;
+	}
+	
+	string toString (wstring str)
+	{
+		return tango.text.convert.Utf.toString(str);
+	}
+	
+	string toString (dstring str)
+	{
+		return tango.text.convert.Utf.toString(str);
+	}
+}*/
+
+version (Phobos)
+{	
+	/**
+	 * Converts the given string to C-style 0 terminated string.
+	 * 
+	 * Params:
+	 *     str = the string to convert
+	 *     
+	 * Returns: the a C-style 0 terminated string.
+	 */
+	dchar* toString32z (dstring str)
+	{
+		return (str ~ '\0').dup.ptr;
+	}
+	
+	/**
+	 * Converts a C-style 0 terminated string to a string
+	 * 
+	 * Params:
+	 *     str = the C-style 0 terminated string
+	 *     
+	 * Returns: the converted string
+	 */
+	string fromStringz (char* str)
+	{
+		return std.conv.to!(string)(str);
+	}
+	
+	/**
+	 * Converts a C-style 0 terminated string to a wstring
+	 * 
+	 * Params:
+	 *     str = the C-style 0 terminated string
+	 *     
+	 * Returns: the converted wstring
+	 */
+	wstring fromString16z (wchar* str)
+	{
+		return str[0 .. strlen(str)].idup;
+	}
+	
+	/**
+	 * Converts a C-style 0 terminated string to a dstring
+	 * Params:
+	 *     str = the C-style 0 terminated string
+	 *     
+	 * Returns: the converted dstring
+	 */
+	dstring fromString32z (dchar* str)
+	{
+		return str[0 .. strlen(str)].idup;
+	}
+	
+	/**
+	 * Gets the length of the given C-style 0 terminated string
+	 * 
+	 * Params:
+	 *     str = the C-style 0 terminated string to get the length of
+	 *     
+	 * Returns: the length of the string
+	 */
+	size_t strlen (wchar* str)
+	{
+		size_t i = 0;
+		
+		if (str)
+			while(*str++)
+				++i;
+		
+		return i;
+	}
+	
+	/**
+	 * Gets the length of the given C-style 0 terminated string
+	 * 
+	 * Params:
+	 *     str = the C-style 0 terminated string to get the length of
+	 *     
+	 * Returns: the length of the string
+	 */
+	size_t strlen (dchar* str)
+	{
+		size_t i = 0;
+		
+		if (str)
+			while(*str++)
+				++i;
+		
+		return i;
+	}
+}
+
+T[] replace (T) (T[] source, dchar match, dchar replacement)
+{
+	static assert(isChar!(T), `The type "` ~ T.stringof ~ `" is not a valid type for this function only strings are accepted`);
+	
+	dchar endOfCodeRange;
+	
+	static if (is(T == wchar))
+	{
+		const encodedLength = 2;
+		endOfCodeRange = wchar.init;
+	}
+	
+	else static if (is(T == char))
+	{
+		const encodedLength = 4;
+		endOfCodeRange = '\x7F';
+	}
+	
+	if (replacement <= endOfCodeRange && match <= endOfCodeRange)
+	{
+		foreach (ref c ; source)
+			if (c == match)
+				c = cast(T) replacement;
+		
+		return source;
+	}
+	
+	else
+	{
+		static if (!is(T == dchar))
+		{
+			T[encodedLength] encodedMatch;
+			T[encodedLength] encodedReplacement;
+			
+			version (Tango)
+				return source.substitute(encode(encodedMatch, match), encode(encodedReplacement, replacement));
+			
+			else
+			{
+				auto matchLength = encode(encodedMatch, match);
+				auto replacementLength = encode(encodedReplacement, replacement);
+				
+				return std.array.replace(source, encodedMatch[0 .. matchLength], encodedReplacement[0 .. replacementLength]);
+			}
+		}
+	}
+	
+	return source;
+}
\ No newline at end of file
--- a/orange/serialization/RegisterWrapper.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/serialization/RegisterWrapper.d	Wed Aug 03 21:58:21 2011 +0200
@@ -6,8 +6,9 @@
  */
 module orange.serialization.RegisterWrapper;
 
-import orange.serialization.archives.Archive;
-import orange.serialization.Serializer;
+//import orange.serialization.archives.Archive;
+//import orange.serialization.Serializer;
+import orange.core.string;
 
 class RegisterBase
 {
@@ -16,22 +17,21 @@
 
 class SerializeRegisterWrapper (T, SerializerType) : RegisterBase
 {
-	private alias SerializerType.DataType DataType;
-	private void delegate (T, SerializerType, DataType) dg;
+	private void delegate (T, SerializerType, string) dg;
 	private bool isDelegate;
 
-	this (void delegate (T, SerializerType, DataType) dg)
+	this (void delegate (T, SerializerType, string) dg)
 	{
 		isDelegate = true;
 		this.dg = dg;
 	}
 
-	this (void function (T, SerializerType, DataType) func)
+	this (void function (T, SerializerType, string) func)
 	{
 		dg.funcptr = func;
 	}
 
-	void opCall (T value, SerializerType archive, DataType key)
+	void opCall (T value, SerializerType archive, string key)
 	{
 		if (dg && isDelegate)
 			dg(value, archive, key);
@@ -43,22 +43,21 @@
 
 class DeserializeRegisterWrapper (T, SerializerType) : RegisterBase
 {
-	private alias SerializerType.DataType DataType;
-	private void delegate (ref T, SerializerType, DataType) dg;
+	private void delegate (ref T, SerializerType, string) dg;
 	private bool isDelegate;
 
-	this (void delegate (ref T, SerializerType, DataType) dg)
+	this (void delegate (ref T, SerializerType, string) dg)
 	{
 		isDelegate = true;
 		this.dg = dg;
 	}
 
-	this (void function (ref T, SerializerType, DataType) func)
+	this (void function (ref T, SerializerType, string) func)
 	{
 		dg.funcptr = func;
 	}
 
-	void opCall (ref T value, SerializerType archive, DataType key)
+	void opCall (ref T value, SerializerType archive, string key)
 	{
 		if (dg && isDelegate)
 			dg(value, archive, key);
--- a/orange/serialization/Serializable.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/serialization/Serializable.d	Wed Aug 03 21:58:21 2011 +0200
@@ -53,6 +53,19 @@
 	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
+package:
+
+version (Tango)
+{
+	const nonSerializedField = "__nonSerialized";
+	const serializedField = "__serialized";
+	const internalFields = [nonSerializedField[], onDeserializedField, onDeserializingField, onSerializedField, onSerializingField];
+}
+
+else
+{
+	mixin(
+	`enum nonSerializedField = "__nonSerialized";
+	enum serializedField = "__serialized";
+	enum internalFields = [nonSerializedField[], onDeserializedField, onDeserializingField, onSerializedField, onSerializingField];`);
+}
\ No newline at end of file
--- a/orange/serialization/SerializationException.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/serialization/SerializationException.d	Wed Aug 03 21:58:21 2011 +0200
@@ -6,7 +6,7 @@
  */
 module orange.serialization.SerializationException;
 
-import orange.util.string;
+import orange.core.string;
 
 version (Tango)
 	alias Exception ExceptionBase;
--- a/orange/serialization/Serializer.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/serialization/Serializer.d	Wed Aug 03 21:58:21 2011 +0200
@@ -12,11 +12,13 @@
 else
 {
 	import std.conv;
-	alias ConvError ConversionException;
+	alias ConvException ConversionException;
 }
 
+import orange.core._;
 import orange.serialization._;
-import orange.serialization.archives._;
+import orange.serialization.archives.Archive;
+import orange.serialization.archives.ArchiveException;
 import orange.util._;
 
 private
@@ -31,78 +33,76 @@
 	
 	alias Mode.serializing serializing;
 	alias Mode.deserializing deserializing;
+	
+	private char toUpper (char c)
+	{
+		if (c >= 'a' && c <= 'z')
+			return cast(char) (c - 32);
+
+		return c;
+	}
 }
 
-class Serializer (ArchiveType : IArchive)
+class Serializer
 {
-	static assert(isArchive!(ArchiveType), format!(`The type "`, ArchiveType, `" does not implement the necessary methods to be an archive.`));
-	
-	alias ArchiveType.ErrorCallback ErrorCallback;
-	alias ArchiveType.DataType DataType;	
+	alias void delegate (ArchiveException exception, string[] data) ErrorCallback;
+	alias Archive.UntypedData Data;
+	alias Archive.Id Id;
 	
 	private
 	{
-		ArchiveType archive;
+		struct ValueMeta
+		{
+			Id id;
+			string key;
+		}
+		
+		ErrorCallback errorCallback_;		
+		Archive archive;
+		
+		size_t keyCounter;
+		Id idCounter;
 		
 		RegisterBase[string] serializers;
 		RegisterBase[string] deserializers;
 		
-		size_t keyCounter;
+		Id[void*] serializedReferences;
+		void*[Id] deserializedReferences;
+		
+		Array[Id] serializedArrays;
+		void[][Id] deserializedSlices;
+		
+		void*[Id] serializedPointers;
+		void**[Id] deserializedPointers;
+		
+		ValueMeta[void*] serializedValues;
+		void*[Id] deserializedValues;
 		
 		bool hasBegunSerializing;
 		bool hasBegunDeserializing;
 		
-		void delegate (ArchiveException exception, DataType[] data) throwOnErrorCallback;		
-		void delegate (ArchiveException exception, DataType[] data) doNothingOnErrorCallback;
+		void delegate (ArchiveException exception, string[] data) throwOnErrorCallback;		
+		void delegate (ArchiveException exception, string[] data) doNothingOnErrorCallback;
 	}
 	
-	this ()
+	this (Archive archive)
 	{
-		archive = new ArchiveType;
+		this.archive = archive;
 		
-		throwOnErrorCallback = (ArchiveException exception, DataType[] data) { throw exception; };
-		doNothingOnErrorCallback = (ArchiveException exception, DataType[] data) { /* do nothing */ };
+		throwOnErrorCallback = (ArchiveException exception, string[] data) { throw exception; };
+		doNothingOnErrorCallback = (ArchiveException exception, string[] data) { /* do nothing */ };
 		
 		setThrowOnErrorCallback();
 	}
-
-	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;
-	}
 	
 	ErrorCallback errorCallback ()
 	{
-		return archive.errorCallback;
+		return errorCallback_;
 	}
 	
 	ErrorCallback errorCallback (ErrorCallback errorCallback)
 	{
-		return archive.errorCallback = errorCallback;
+		return errorCallback_ = errorCallback;
 	}
 	
 	void setThrowOnErrorCallback ()
@@ -115,44 +115,69 @@
 		errorCallback = doNothingOnErrorCallback;
 	}
 	
-	DataType serialize (T) (T value, DataType key = null)
+	void reset ()
+	{
+		resetCounters();
+		
+		serializers = null;
+		deserializers = null;
+		
+		serializedReferences = null;
+		deserializedReferences = null;
+		
+		serializedArrays = null;
+		deserializedSlices = null;
+		
+		serializedValues = null;
+		serializedPointers = null;
+		
+		hasBegunSerializing = false;
+		hasBegunDeserializing = false;
+		
+		archive.reset;
+	}
+	
+	Data serialize (T) (T value, string key = null)
 	{
 		if (!hasBegunSerializing)
 			hasBegunSerializing = true;
 		
 		serializeInternal(value, key);
-		archive.postProcess;
+		postProcess;
 
-		return archive.data;
+		return archive.untypedData;
 	}
 	
-	private void serializeInternal (T) (T value, DataType key = null)
+	private void serializeInternal (T) (T value, string key = null, Id id = Id.max)
 	{
 		if (!key)
 			key = nextKey;
-		
+
+		if (id == Id.max)
+			id = nextId;
+
 		archive.beginArchiving();
+
+		static if ( is(T == typedef) )
+			serializeTypedef(value, key, id);
 		
-		static if (isTypeDef!(T))
-			serializeTypeDef(value, key);
-		
-		static if (isObject!(T))
-			serializeObject(value, key);
+		else static if (isObject!(T))
+			serializeObject(value, key, id);
 
 		else static if (isStruct!(T))
-			serializeStruct(value, key);
+			serializeStruct(value, key, id);
 
 		else static if (isString!(T))
-			serializeString(value, key);
+			serializeString(value, key, id);
 		
 		else static if (isArray!(T))
-			serializeArray(value, key);
+			serializeArray(value, key, id);
 
 		else static if (isAssociativeArray!(T))
-			serializeAssociativeArray(value, key);
+			serializeAssociativeArray(value, key, id);
 
 		else static if (isPrimitive!(T))
-			serializePrimitive(value, key);
+			serializePrimitive(value, key, id);
 
 		else static if (isPointer!(T))
 		{
@@ -160,11 +185,11 @@
 				goto error;
 				
 			else
-				serializePointer(value, key);
-		}			
+				serializePointer(value, key, id);
+		}
 		
 		else static if (isEnum!(T))
-			serializeEnum(value, key);
+			serializeEnum(value, key, id);
 		
 		else
 		{
@@ -172,13 +197,23 @@
 			throw new SerializationException(format!(`The type "`, T, `" cannot be serialized.`), __FILE__, __LINE__);
 		}
 	}
-	
-	private void serializeObject (T) (T value, DataType key)
-	{			
-		triggerEvents(serializing, value, {
-			archive.archive(value, key, {
-				auto runtimeType = value.classinfo.name;
 
+	private void serializeObject (T) (T value, string key, Id id)
+	{
+		if (!value)
+			return archive.archiveNull(T.stringof, key);
+		
+		auto reference = getSerializedReference(value);
+		
+		if (reference != Id.max)
+			return archive.archiveReference(key, reference);
+		
+		auto runtimeType = value.classinfo.name;
+		
+		addSerializedReference(value, id);
+
+		triggerEvents(serializing, value, {			
+			archive.archiveObject(runtimeType, T.stringof, key, id, {
 				if (runtimeType in serializers)
 				{
 					auto wrapper = getSerializerWrapper!(T)(runtimeType);
@@ -192,19 +227,19 @@
 				{				
 					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);
 				}
 			});
 		});
 	}
-
-	private void serializeStruct (T) (T value, DataType key)
-	{		
+	
+	private void serializeStruct (T) (T value, string key, Id id)
+	{			
+		string type = T.stringof;
+		
 		triggerEvents(serializing, value, {
-			archive.archive(value, key, {
-				auto type = toDataType(T.stringof);
-				
+			archive.archiveStruct(type, key, id, {
 				if (type in serializers)
 				{
 					auto wrapper = getSerializerWrapper!(T)(type);
@@ -223,30 +258,69 @@
 		});
 	}
 	
-	private void serializeString (T) (T value, DataType key)
+	private void serializeString (T) (T value, string key, Id id)
 	{
-		archive.archive(value, key);
+		auto array = Array(cast(void*) value.ptr, value.length, ElementTypeOfArray!(T).sizeof);
+		
+		archive.archive(value, key, id);			
+		addSerializedArray(array, id);
 	}
+	
+	private void serializeArray (T) (T value, string key, Id id)
+	{
+		auto array = Array(value.ptr, value.length, ElementTypeOfArray!(T).sizeof);
+
+		archive.archiveArray(array, arrayToString!(T), key, id, {
+			foreach (i, e ; value)
+				serializeInternal(e, toData(i));
+		});
 
-	private void serializeArray (T) (T value, DataType key)
+		addSerializedArray(array, id);
+	}
+	
+	private void serializeAssociativeArray (T) (T value, string key, Id id)
 	{
-		archive.archive(value, key, {
-			foreach (i, e ; value)
-				serializeInternal(e, toDataType(i));
+		auto reference = getSerializedReference(value);
+		
+		if (reference != Id.max)
+			return archive.archiveReference(key, reference);
+
+		addSerializedReference(value, id);
+		
+		string keyType = KeyTypeOfAssociativeArray!(T).stringof;
+		string valueType = ValueTypeOfAssociativeArray!(T).stringof;
+		
+		archive.archiveAssociativeArray(keyType, valueType, value.length, key, id, {
+			size_t i;
+			
+			foreach(k, v ; value)
+			{
+				archive.archiveAssociativeArrayKey(toData(i), {
+					serializeInternal(k, toData(i));
+				});
+				
+				archive.archiveAssociativeArrayValue(toData(i), {
+					serializeInternal(v, toData(i));
+				});
+				
+				i++;
+			}
 		});
 	}
-
-	private void serializeAssociativeArray (T) (T value, DataType key)
+	
+	private void serializePointer (T) (T value, string key, Id id)
 	{
-		archive.archive(value, key, {
-			foreach(k, v ; value)
-				serializeInternal(v, toDataType(k));
-		});
-	}
+		if (!value)
+			return archive.archiveNull(T.stringof, key);
+		
+		auto reference = getSerializedReference(value);
+		
+		if (reference != Id.max)
+			return archive.archiveReference(key, reference);
 
-	private void serializePointer (T) (T value, DataType key)
-	{
-		archive.archive(value, key, {
+		addSerializedReference(value, id);
+
+		archive.archivePointer(key, id, {
 			if (key in serializers)
 			{
 				auto wrapper = getSerializerWrapper!(T)(key);
@@ -262,29 +336,35 @@
 					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
-					serializeInternal(*value, key);
-			}				
+					serializeInternal(*value, nextKey);
+			}
+		});
+		
+		addSerializedPointer(value, id);
+	}
+	
+	private void serializeEnum (T) (T value, string key, Id id)
+	{
+		alias BaseTypeOfEnum!(T) EnumBaseType;
+		auto val = cast(EnumBaseType) value;
+		string type = T.stringof;
+		
+		archive.archiveEnum(val, type, key, id);
+	}
+	
+	private void serializePrimitive (T) (T value, string key, Id id)
+	{
+		archive.archive(value, key, id);
+	}
+	
+	private void serializeTypedef (T) (T value, string key, Id id)
+	{
+		archive.archiveTypedef(T.stringof, key, nextId, {
+			serializeInternal!(BaseTypeOfTypedef!(T))(value, nextKey);
 		});
 	}
 	
-	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, {
-			serializeInternal!(BaseTypeOfTypeDef!(T))(value, key);
-		});
-	}
-	
-	T deserialize (T) (DataType data, DataType key = null)
+	T deserialize (T) (Data data, string key = null)
 	{		
 		if (hasBegunSerializing && !hasBegunDeserializing)
 			resetCounters();
@@ -294,87 +374,103 @@
 		
 		if (!key)
 			key = nextKey;
-		
+
 		archive.beginUnarchiving(data);
-		return deserializeInternal!(T)(key);
+		auto value = deserializeInternal!(T)(key);
+		deserializingPostProcess;
+		
+		return value;
 	}
 	
-	private T deserializeInternal (T) (DataType key)
-	{
-		static if (isTypeDef!(T))
-			return deserializeTypeDef!(T)(key);
-		
+	private T deserializeInternal (T, U) (U keyOrId)
+	{		
+		static if (isTypedef!(T))
+			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:
 			throw new SerializationException(format!(`The type "`, T, `" cannot be deserialized.`), __FILE__, __LINE__);
 		}			
 	}
+	
+	private T deserializeObject (T, U) (U keyOrId)
+	{
+		auto id = deserializeReference(keyOrId);
 
-	private T deserializeObject (T) (DataType key)
-	{		
-		T value = archive.unarchive!(T)(key, (T value) {			
+		if (auto reference = getDeserializedReference!(T)(id))
+			return *reference;
+
+		T value;
+		Object val = value;
+		nextId;
+		
+		archive.unarchiveObject(keyOrId, 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);
+					wrapper(value, this, keyOrId);
 				}
 				
 				else static if (isSerializable!(T, Serializer))
-					value.fromData(this, key);
+					value.fromData(this, keyOrId);
 				
 				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);					
 				}
 			});
-			
-			return value;
 		});
 		
+		addDeserializedReference(value, id);
+		
 		return value;
 	}
-
-	private T deserializeStruct (T) (DataType key)
-	{		
-		return archive.unarchive!(T)(key, (T value) {			
+	
+	private T deserializeStruct (T) (string key)
+	{
+		T value;
+		nextId;
+		
+		archive.unarchiveStruct(key, {			
 			triggerEvents(deserializing, value, {
-				auto type = toDataType(T.stringof);
+				auto type = toData(T.stringof);
 				
 				if (type in deserializers)
 				{
@@ -391,39 +487,132 @@
 						objectStructDeserializeHelper(value);
 				}	
 			});
-			
-			return value;
 		});
+		
+		return value;
 	}
 	
-	private T deserializeString (T) (DataType key)
+	private T deserializeString (T) (string key)
 	{
-		return archive.unarchive!(T)(key);
-	}
+		auto slice = deserializeSlice(key);
+
+		if (auto tmp = getDeserializedSlice!(T)(slice))
+			return *tmp;
+		
+		T value;
+		
+		if (slice.id != size_t.max)
+		{
+			static if (is(T == string))
+				value = toSlice(archive.unarchiveString(slice.id), slice);
+			
+			else static if (is(T == wstring))
+				value = toSlice(archive.unarchiveWstring(slice.id), slice);
+			
+			else static if (is(T == dstring))
+				value = toSlice(archive.unarchiveDstring(slice.id), slice);
+		}
+		
+		else
+		{
+			static if (is(T == string))
+				value = archive.unarchiveString(key, slice.id);
+			
+			else static if (is(T == wstring))
+				value = archive.unarchiveWstring(key, slice.id);
+			
+			else static if (is(T == dstring))
+				value = archive.unarchiveDstring(key, slice.id);
+		}		
 
-	private T deserializeArray (T) (DataType key)
+		addDeserializedSlice(value, slice.id);
+		
+		return value;
+	}
+	
+	private T deserializeArray (T) (string key)
 	{
-		return archive.unarchive!(T)(key, (T value) {
+		auto slice = deserializeSlice(key);
+		
+		if (auto tmp = getDeserializedSlice!(T)(slice))
+			return *tmp;
+		
+		T value;
+
+		auto dg = (size_t length) {
+			value.length = length;
+
 			foreach (i, ref e ; value)
-				e = deserializeInternal!(typeof(e))(toDataType(i));
+				e = deserializeInternal!(typeof(e))(toData(i));
+		};
+		
+		if (slice.id != size_t.max)
+		{
+			archive.unarchiveArray(slice.id, dg);
+			addDeserializedSlice(value, slice.id);
+
+			return toSlice(value, slice);
+		}			
+		
+		else
+		{
+			slice.id = archive.unarchiveArray(key, dg);
+			
+			if (auto a = slice.id in deserializedSlices)
+				return cast(T) *a;
+			
+			addDeserializedSlice(value, slice.id);
 			
 			return value;
-		});	
+		}
 	}
+	
+	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;
+		
+		id = archive.unarchiveAssociativeArray(key, (size_t length) {
+			for (size_t i = 0; i < length; i++)
+			{
+				Key aaKey;
+				Value aaValue;
+				auto k = toData(i);
+				
+				archive.unarchiveAssociativeArrayKey(k, {
+					aaKey = deserializeInternal!(Key)(k);
+				});
+				
+				archive.unarchiveAssociativeArrayValue(k, {
+					aaValue = deserializeInternal!(Value)(k);
+				});
+				
+				value[aaKey] = aaValue;
+			}
+		});
+		
+		addDeserializedReference(value, id);
+		
+		return value;
+	}
+	
+	private T deserializePointer (T) (string key, out Id id)
+	{
+		id = deserializeReference(key);
 
-	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 (auto reference = getDeserializedReference!(T)(id))
+			return *reference;
+		
+		T value = new BaseTypeOfPointer!(T);
+		
+		auto pointerId = archive.unarchivePointer(key, {
 			if (key in deserializers)
 			{
 				auto wrapper = getDeserializerWrapper!(T)(key);
@@ -439,45 +628,85 @@
 					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);
+				{
+					auto k = nextKey;
+					id = deserializeReference(k);
+
+					if (id != Id.max)
+						return;
+
+					*value = deserializeInternal!(BaseTypeOfPointer!(T))(k);
+				}
 			}
-			
-			return value;
 		});
+
+		addDeserializedReference(value, pointerId);
+
+		return value;
+	}
+	
+	private T deserializeEnum (T) (string key)
+	{
+		alias BaseTypeOfEnum!(T) Enum;
+
+		const functionName = toUpper(Enum.stringof[0]) ~ Enum.stringof[1 .. $];
+		mixin("return cast(T) archive.unarchiveEnum" ~ functionName ~ "(key);");
 	}
 	
-	private T deserializeEnum (T) (DataType key)
+	private T deserializePrimitive (T, U) (U keyOrId)
 	{
-		return archive.unarchive!(T)(key);
-	}
-
-	private T deserializePrimitive (T) (DataType key)
-	{		
-		return archive.unarchive!(T)(key);
+		const functionName = toUpper(T.stringof[0]) ~ T.stringof[1 .. $];
+		mixin("return archive.unarchive" ~ functionName ~ "(keyOrId);");
 	}
 	
-	private T deserializeTypeDef (T) (DataType key)
+	private T deserializeTypedef (T, U) (U keyOrId)
 	{
-		return archive.unarchive!(T)(key, (T value) {
-			return deserializeInternal!(BaseTypeOfTypeDef!(T))(key);
+		T value;
+		
+		archive.unarchiveTypedef!(T)(key, {
+			value = cast(T) deserializeInternal!(BaseTypeOfTypedef!(T))(nextKey);
 		});
+		
+		return value;
+	}
+	
+	private Id deserializeReference (string key)
+	{
+		return archive.unarchiveReference(key);
+	}
+	
+	private Slice deserializeSlice (string key)
+	{
+		return archive.unarchiveSlice(key);
 	}
 	
 	private void objectStructSerializeHelper (T) (ref T value)
 	{
 		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.`));
-		const nonSerializedFields = collectAnnotations!(nonSerializedField, T);
+		
+		version (Tango)
+			const nonSerializedFields = collectAnnotations!(nonSerializedField, T);
+			
+		else
+			mixin(`enum nonSerializedFields = collectAnnotations!(nonSerializedField, T);`);
 		
 		foreach (i, dummy ; typeof(T.tupleof))
 		{
-			const field = nameOfFieldAt!(T, i);
+			version (Tango)
+				const field = nameOfFieldAt!(T, i);
+				
+			else
+				mixin(`enum field = nameOfFieldAt!(T, i);`);
 			
-			static if (!internalFields.ctfeContains(field) && !nonSerializedFields.ctfeContains(field))
+			static if (!ctfeContains!(string)(internalFields, field) && !ctfeContains!(string)(nonSerializedFields, field))
 			{
 				alias typeof(T.tupleof[i]) Type;				
-				Type v = value.tupleof[i];
-				serializeInternal(v, toDataType(field));
-			}				
+				Type v = value.tupleof[i];				
+				auto id = nextId;
+
+				addSerializedValue(value.tupleof[i], id, toData(keyCounter));
+				serializeInternal(v, toData(field), id);
+			}
 		}
 		
 		static if (isObject!(T) && !is(T == Object))
@@ -487,20 +716,42 @@
 	private void objectStructDeserializeHelper (T) (ref T value)
 	{		
 		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.`));
-		const nonSerializedFields = collectAnnotations!(nonSerializedField, T);
+				
+		version (Tango)
+			const nonSerializedFields = collectAnnotations!(nonSerializedField, T);
+			
+		else
+			mixin(`enum nonSerializedFields = collectAnnotations!(nonSerializedField, T);`);
 		
 		foreach (i, dummy ; typeof(T.tupleof))
 		{
-			const field = nameOfFieldAt!(T, i);
+			version (Tango)
+				const field = nameOfFieldAt!(T, i);
+				
+			else
+				mixin(`enum field = nameOfFieldAt!(T, i);`);
 						
-			static if (!internalFields.ctfeContains(field) && !nonSerializedFields.ctfeContains(field))
+			static if (!ctfeContains!(string)(internalFields, field) && !ctfeContains!(string)(nonSerializedFields, field))
 			{
 				alias TypeOfField!(T, field) Type;
-				auto fieldValue = deserializeInternal!(Type)(toDataType(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);
 	}
@@ -508,10 +759,10 @@
 	private void serializeBaseTypes (T : Object) (T value)
 	{
 		alias BaseTypeTupleOf!(T)[0] Base;
-		
+
 		static if (!is(Base == Object))
 		{
-			archive.archiveBaseClass!(Base)(nextKey);
+			archive.archiveBaseClass(Base.stringof, nextKey, nextId);
 			Base base = value;
 			objectStructSerializeHelper(base);
 		}
@@ -527,6 +778,90 @@
 			Base base = value;
 			objectStructDeserializeHelper(base);
 		}
+	}	
+	
+	private void addSerializedReference (T) (T value, Id id)
+	{
+		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) || isAssociativeArray!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object, pointer or associative array.`));
+		
+		deserializedReferences[id] = cast(void*) value;
+	}
+	
+	private void addDeserializedSlice (T) (T value, Id id)
+	{
+		static assert(isArray!(T) || isString!(T), format!(`The given type "`, T, `" is not a slice type, i.e. array or string.`));
+
+		deserializedSlices[id] = cast(void[]) value;
+	}
+	
+	private void addSerializedValue (T) (ref T value, Id id, string key)
+	{
+		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)
+	{
+		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)
+			return *tmp;
+		
+		return Id.max;
+	}
+	
+	private T* getDeserializedReference (T) (Id id)
+	{
+		if (auto reference = id in deserializedReferences)
+			return cast(T*) reference;
+		
+		return null;
+	}
+	
+	private T* getDeserializedSlice (T) (Slice slice)
+	{
+		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
+		return null;		
+	}
+	
+	private T* getDeserializedArray (T) (Id id)
+	{
+		if (auto array = id in deserializedSlices)
+			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];
 	}
 	
 	private SerializeRegisterWrapper!(T, Serializer) getSerializerWrapper (T) (string type)
@@ -549,33 +884,95 @@
 		assert(false, "throw exception here");
 	}
 	
-	private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void delegate (T, Serializer, DataType) dg)
+	private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void delegate (T, Serializer, string) dg)
 	{		
 		return new SerializeRegisterWrapper!(T, Serializer)(dg);
 	}
 
-	private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void function (T, Serializer, DataType) func)
+	private SerializeRegisterWrapper!(T, Serializer) toSerializeRegisterWrapper (T) (void function (T, Serializer, string) func)
 	{		
 		return new SerializeRegisterWrapper!(T, Serializer)(func);
 	}
 
-	private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void delegate (ref T, Serializer, DataType) dg)
+	private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void delegate (ref T, Serializer, string) dg)
 	{		
 		return new DeserializeRegisterWrapper!(T, Serializer)(dg);
 	}
 
-	private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void function (ref T, Serializer, DataType) func)
+	private DeserializeRegisterWrapper!(T, Serializer) toDeserializeRegisterWrapper (T) (void function (ref T, Serializer, string) func)
 	{		
 		return new DeserializeRegisterWrapper!(T, Serializer)(func);
 	}
 	
-	private DataType toDataType (T) (T value)
+	private void addSerializedArray (Array array, Id id)
+	{
+		serializedArrays[id] = array;
+	}
+	
+	private void postProcess ()
+	{
+		postProcessArrays();
+		postProcessPointers();
+	}
+	
+	private void postProcessArrays ()
 	{
-		try
-			return to!(DataType)(value);
+		bool foundSlice = true;
 		
-		catch (ConversionException e)
-			throw new SerializationException(e);
+		foreach (sliceKey, slice ; serializedArrays)
+		{
+			foreach (arrayKey, array ; serializedArrays)
+			{
+				if (slice.isSliceOf(array) && slice != array)
+				{
+					auto s = Slice(slice.length, (slice.ptr - array.ptr) / slice.elementSize);
+					archive.archiveSlice(s, sliceKey, arrayKey);
+					foundSlice = true;
+					break;
+				}
+				
+				else
+					foundSlice = false;
+			}
+			
+			if (!foundSlice)
+				archive.postProcessArray(sliceKey);
+		}
+	}
+	
+	private void postProcessPointers ()
+	{
+		foreach (pointerId, value ; serializedPointers)
+		{
+			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)
+	{
+		version (Tango)
+			const arrayToString = ElementTypeOfArray!(T).stringof;
+			
+		else
+			mixin(`enum arrayToString = ElementTypeOfArray!(T).stringof;`);
 	}
 	
 	private bool isBaseClass (T) (T value)
@@ -586,14 +983,30 @@
 		return T.stringof != name[index + 1 .. $];
 	}
 	
-	private DataType nextKey ()
+	private Id nextId ()
+	{
+		return idCounter++;
+	}
+	
+	private string nextKey ()
 	{
-		return toDataType(keyCounter++);
+		return toData(keyCounter++);
+	}
+	
+	private string prevKey ()
+	{
+		return toData(--keyCounter);
 	}
 	
 	private void resetCounters ()
 	{
 		keyCounter = 0;
+		idCounter = 0;
+	}
+	
+	private string toData (T) (T value)
+	{
+		return to!(string)(value);
 	}
 	
 	private void triggerEvent (string name, T) (T value)
@@ -620,9 +1033,9 @@
 		
 		else
 			triggerEvent!(onDeserializingField)(value);
-		
+
 		dg();
-		
+
 		if (mode == serializing)
 			triggerEvent!(onSerializedField)(value);
 		
--- a/orange/serialization/archives/Archive.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/serialization/archives/Archive.d	Wed Aug 03 21:58:21 2011 +0200
@@ -12,56 +12,198 @@
 else
 {
 	import std.conv;
-	alias ConvError ConversionException;
+	alias ConvException ConversionException;
 }
 
 import orange.serialization.archives.ArchiveException;
+import orange.core.string;
+
+private enum ArchiveMode
+{
+	archiving,
+	unarchiving
+}
+
+struct Array
+{
+	version (Tango)
+		void* ptr;
+		
+	else
+		mixin(`const(void)* ptr;`);
+
+	size_t length;
+	size_t elementSize;
+	
+	bool isSliceOf (Array b)
+	{
+		return ptr >= b.ptr && ptr + length * elementSize <= b.ptr + b.length * b.elementSize;
+	}
+}
 
 struct Slice
 {
 	size_t length;
-	void* ptr;
-	
-	static Slice opCall (T) (T[] value)
-	{
-		Slice slice;
-		slice.length = value.length;
-		slice.ptr = value.ptr;
-		
-		return slice;
-	}
-}
-
-interface IArchive
-{
-	void beginArchiving ();
-	void reset ();
+	size_t offset;
+	size_t id = size_t.max;
 }
 
-abstract class Archive (U) : IArchive
+interface Archive
 {
-	version (Tango) alias U[] DataType;
-	else mixin ("alias immutable(U)[] DataType;");
+	alias size_t Id;
+	
+	version (Tango) alias void[] UntypedData;
+	else mixin ("alias immutable(void)[] UntypedData;");
+	
+	void beginArchiving ();
+	void beginUnarchiving (UntypedData data);
+	
+	UntypedData untypedData ();
+	void reset ();
+	
+	void archiveArray (Array array, string type, string key, Id id, void delegate () dg);
+	void archiveAssociativeArray (string keyType, string valueType, size_t length, string key, Id id, void delegate () dg);
+	void archiveAssociativeArrayKey (string key, void delegate () dg);
+	void archiveAssociativeArrayValue (string key, void delegate () dg);
+	
+	void archiveEnum (bool value, string baseType, string key, Id id);
+	void archiveEnum (byte value, string baseType, string key, Id id);
+	void archiveEnum (char value, string baseType, string key, Id id);
+	void archiveEnum (dchar value, string baseType, string key, Id id);
+	void archiveEnum (int value, string baseType, string key, Id id);
+	void archiveEnum (long value, string baseType, string key, Id id);
+	void archiveEnum (short value, string baseType, string key, Id id);
+	void archiveEnum (ubyte value, string baseType, string key, Id id);
+	void archiveEnum (uint value, string baseType, string key, Id id);
+	void archiveEnum (ulong value, string baseType, string key, Id id);
+	void archiveEnum (ushort value, string baseType, string key, Id id);
+	void archiveEnum (wchar value, string baseType, string key, Id id);
 	
-	alias void delegate (ArchiveException exception, DataType[] data) ErrorCallback;
+	void archiveBaseClass (string type, string key, Id id);
+	void archiveNull (string type, string key);
+	void archiveObject (string runtimeType, string type, string key, Id id, void delegate () dg);
+	void archivePointer (string key, Id id, void delegate () dg);
+	void archivePointer (Id pointeeId, string key, Id id);
+	void archiveReference (string key, Id id);
+	void archiveSlice (Slice slice, Id sliceId, Id arrayId);
+	void archiveStruct (string type, string key, Id id, void delegate () dg);
+	void archiveTypedef (string type, string key, Id id, void delegate () dg);
+
+	void archive (string value, string key, Id id);
+	void archive (wstring value, string key, Id id);
+	void archive (dstring value, string key, Id id);	
+	void archive (bool value, string key, Id id);
+	void archive (byte value, string key, Id id);
+	//void archive (cdouble value, string key, Id id); // currently not supported by to!()
+	//void archive (cent value, string key, Id id);
+	//void archive (cfloat value, string key, Id id); // currently not supported by to!()
+	void archive (char value, string key, Id id); // currently not implemented but a reserved keyword
+	//void archive (creal value, string key, Id id); // currently not supported by to!()
+	void archive (dchar value, string key, Id id);
+	void archive (double value, string key, Id id);
+	void archive (float value, string key, Id id);
+	//void archive (idouble value, string key, Id id); // currently not supported by to!()
+	//void archive (ifloat value, string key, Id id); // currently not supported by to!()
+	void archive (int value, string key, Id id);
+	//void archive (ireal value, string key, Id id); // currently not supported by to!()
+	void archive (long value, string key, Id id);
+	void archive (real value, string key, Id id);
+	void archive (short value, string key, Id id);
+	void archive (ubyte value, string key, Id id);
+	//void archive (ucent value, string key, Id id); // currently not implemented but a reserved keyword
+	void archive (uint value, string key, Id id);
+	void archive (ulong value, string key, Id id);
+	void archive (ushort value, string key, Id id);
+	void archive (wchar value, string key, Id id);
+	
+	Id unarchiveArray (string key, void delegate (size_t length) dg);
+	void unarchiveArray (Id id, 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);
 	
-	ErrorCallback errorCallback;
+	bool unarchiveEnumBool (string key);
+	byte unarchiveEnumByte (string key);
+	char unarchiveEnumChar (string key);
+	dchar unarchiveEnumDchar (string key);
+	int unarchiveEnumInt (string key);
+	long unarchiveEnumLong (string key);
+	short unarchiveEnumShort (string key);
+	ubyte unarchiveEnumUbyte (string key);
+	uint unarchiveEnumUint (string key);
+	ulong unarchiveEnumUlong (string key);
+	ushort unarchiveEnumUshort (string key);
+	wchar unarchiveEnumWchar (string key);
+	
+	// Object unarchiveBaseClass (string key);
+	// void unarchiveNull (string key);
+	void unarchiveObject (string key, out Id id, out Object result, void delegate () dg);
+	Id unarchivePointer (string key, void delegate () dg);
+	Id unarchiveReference (string key);
+	Slice unarchiveSlice (string key);
+	void unarchiveStruct (string key, void delegate () dg);
+	void unarchiveTypedef (string key, void delegate () dg);
+	
+	string unarchiveString (string key, out Id id);
+	wstring unarchiveWstring (string key, out Id id);
+	dstring unarchiveDstring (string key, out Id id);
 	
-	abstract void beginArchiving ();
-	abstract void beginUnarchiving (DataType data);
-	abstract DataType data ();
-	abstract void reset ();
+	string unarchiveString (Id id);
+	wstring unarchiveWstring (Id id);
+	dstring unarchiveDstring (Id id);
+    bool unarchiveBool (string key);
+    byte unarchiveByte (string key);
+    //cdouble unarchiveCdouble (string key); // currently not supported by to!()
+    //cent unarchiveCent (string key); // currently not implemented but a reserved keyword
+    //cfloat unarchiveCfloat (string key); // currently not supported by to!()
+    char unarchiveChar (string key); // currently not implemented but a reserved keyword
+    //creal unarchiveCreal (string key); // currently not supported by to!()
+    dchar unarchiveDchar (string key);
+    double unarchiveDouble (string key);
+    float unarchiveFloat (string key);
+    //idouble unarchiveIdouble (string key); // currently not supported by to!()
+    //ifloat unarchiveIfloat (string key); // currently not supported by to!()*/
+    int unarchiveInt (string key);
+	//int unarchiveInt (Id id);
+    //ireal unarchiveIreal (string key); // currently not supported by to!()
+    long unarchiveLong (string key);
+    real unarchiveReal (string key);
+    short unarchiveShort (string key);
+    ubyte unarchiveUbyte (string key);
+    //ucent unarchiveCcent (string key); // currently not implemented but a reserved keyword
+    uint unarchiveUint (string key);
+    ulong unarchiveUlong (string key);
+    ushort unarchiveUshort (string key);
+    wchar unarchiveWchar (string key);
 	
-	protected DataType toDataType (T) (T value)
+	void postProcessArray (Id id);
+	void postProcessPointer (Id id);
+}
+
+abstract class Base (U) : Archive
+{
+	version (Tango) alias U[] Data;
+	else mixin ("alias immutable(U)[] Data;");
+	
+	alias void delegate (ArchiveException exception, string[] data) ErrorCallback;
+	
+	protected ErrorCallback errorCallback;
+	
+	protected this (ErrorCallback errorCallback)
+	{
+		this.errorCallback = errorCallback;
+	}
+	
+	protected Data toData (T) (T value)
 	{
 		try
-			return to!(DataType)(value);
+			return to!(Data)(value);
 		
 		catch (ConversionException e)
 			throw new ArchiveException(e);
 	}
 	
-	protected T fromDataType (T) (DataType value)
+	protected T fromData (T) (Data value)
 	{
 		try
 			return to!(T)(value);
@@ -70,6 +212,11 @@
 			throw new ArchiveException(e);
 	}
 	
+	protected Id toId (Data value)
+	{
+		return fromData!(Id)(value);
+	}
+	
 	protected bool isSliceOf (T, U = T) (T[] a, U[] b)
 	{
 		void* aPtr = a.ptr;
--- a/orange/serialization/archives/ArchiveException.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/serialization/archives/ArchiveException.d	Wed Aug 03 21:58:21 2011 +0200
@@ -7,7 +7,7 @@
 module orange.serialization.archives.ArchiveException;
 
 import orange.serialization.SerializationException;
-import orange.util.string;
+import orange.core.string;
 
 class ArchiveException : SerializationException
 {	
--- a/orange/serialization/archives/XMLArchive.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/serialization/archives/XMLArchive.d	Wed Aug 03 21:58:21 2011 +0200
@@ -12,112 +12,79 @@
 else
 	import std.conv;
 
+import orange.core._;
 import orange.serialization.archives._;
+import orange.serialization.Serializer;
 import orange.util._;
 import orange.xml.XMLDocument;
 
-private enum ArchiveMode
+final class XMLArchive (U = char) : Base!(U)
 {
-	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 alias Archive.Id Id;
+	
 	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";
-		static const DataType sliceTag = "slice";
+		static const Data structTag = "struct";	
+		static const Data dataTag = "data";
+		static const Data archiveTag = "archive";
+		static const Data arrayTag = "array";
+		static const Data objectTag = "object";
+		static const Data baseTag = "base";
+		static const Data stringTag = "string";
+		static const Data referenceTag = "reference";
+		static const Data pointerTag = "pointer";
+		static const Data associativeArrayTag = "associativeArray";
+		static const Data typedefTag = "typedef";
+		static const Data nullTag = "null";
+		static const Data enumTag = "enum";
+		static const Data sliceTag = "slice";
+		static const Data elementTag = "element";
+		static const Data keyTag = "key";
+		static const Data valueTag = "value";
 	}
 
 	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";
-		static const DataType offsetAttribute = "offset";
+		static const Data invalidAttribute = "\0";
+		static const Data typeAttribute = "type";
+		static const Data versionAttribute = "version";
+		static const Data lengthAttribute = "length";
+		static const Data keyAttribute = "key";
+		static const Data runtimeTypeAttribute = "runtimeType";
+		static const Data idAttribute = "id";
+		static const Data keyTypeAttribute = "keyType";
+		static const Data valueTypeAttribute = "valueType";
+		static const Data offsetAttribute = "offset";
+		static const Data baseTypeAttribute = "baseType";
+	}
+	
+	private struct Node
+	{
+		XMLDocument!(U).Node parent;
+		XMLDocument!(U).Node node;
+		Id id;
+		string key;
 	}
 	
 	private
 	{
-		struct ArrayNode
-		{
-			XMLDocument!(U).Node parent;
-			XMLDocument!(U).Node node;
-			DataType id;
-			DataType key;
-		}
-		
-		struct Array
-		{
-			void* ptr;
-			size_t length;
-			size_t elementSize;
-			
-			static Array opCall (T) (T[] value)
-			{
-				Array array;
-				array.ptr = value.ptr;
-				array.length = value.length;
-				array.elementSize = T.sizeof;
-				
-				return array;
-			}
-			
-			bool isSliceOf (Array b)
-			{
-				return ptr >= b.ptr && ptr + length * elementSize <= b.ptr + b.length * b.elementSize;
-			}
-		}
-		
-		struct Slice
-		{
-			size_t length;
-			size_t offset;
-			DataType id;
-		}
-		
-		DataType archiveType = "org.dsource.orange.xml";
-		DataType archiveVersion = "0.1";
+		Data archiveType = "org.dsource.orange.xml";
+		Data archiveVersion = "1.0.0";
 		
 		XMLDocument!(U) doc;
 		doc.Node lastElement;
-		//DocPrinter!(U) printer;
-		doc.Node lastElementSaved;
 		
 		bool hasBegunArchiving;
 		bool hasBegunUnarchiving;
 		
-		DataType[void*] archivedReferences;
-		void*[DataType] unarchivedReferences;
-		
-		ArrayNode[Array] arraysToBeArchived;
-		void[][DataType] unarchivedSlices;
-		
-		size_t idCounter;
+		Node[Id] archivedArrays;
+		Node[Id] archivedPointers;
+		void[][Data] unarchivedSlices;
 	}
 	
-	this ()
+	this (ErrorCallback errorCallback = null)
 	{
+		super(errorCallback);
 		doc = new XMLDocument!(U);
 	}
 	
@@ -135,8 +102,10 @@
 		}		
 	}
 	
-	public void beginUnarchiving (DataType data)
+	public void beginUnarchiving (UntypedData untypedData)
 	{
+		auto data = cast(Data) untypedData;
+		
 		if (!hasBegunUnarchiving)
 		{
 			doc.parse(data);	
@@ -151,411 +120,683 @@
 			{
 				if (errorCallback)
 				{
+					auto dataTag = to!(string)(Tags.dataTag);
+					
 					if (set.nodes.length == 0)
-						errorCallback(new ArchiveException(errorMessage!(ArchiveMode.unarchiving) ~ `The "` ~ to!(string)(Tags.dataTag) ~ `" tag could not be found.`, __FILE__, __LINE__), [Tags.dataTag]);
+						errorCallback(new ArchiveException(errorMessage!(ArchiveMode.unarchiving) ~ `The "` ~ to!(string)(Tags.dataTag) ~ `" tag could not be found.`, __FILE__, __LINE__), [dataTag]);
 					
 					else
-						errorCallback(new ArchiveException(errorMessage!(ArchiveMode.unarchiving) ~ `There were more than one "` ~ to!(string)(Tags.dataTag) ~ `" tag.`, __FILE__, __LINE__), [Tags.dataTag]);
+						errorCallback(new ArchiveException(errorMessage!(ArchiveMode.unarchiving) ~ `There were more than one "` ~ to!(string)(Tags.dataTag) ~ `" tag.`, __FILE__, __LINE__), [dataTag]);
 				}	
 			}
 		}
 	}
 	
-	public DataType data ()
+	UntypedData untypedData ()
 	{
-		/*if (!printer)
-			printer = new DocPrinter!(U);
-		
-		return printer.print(doc);*/
-		
 		return doc.toString();
 	}
 	
-	public void reset ()
+	Data data ()
+	{
+		return doc.toString;
+	}
+	
+	void reset ()
 	{
 		hasBegunArchiving = false;
 		hasBegunUnarchiving = false;
-		idCounter = 0;
 		doc.reset;
 	}
 	
-	private void begin ()
-	{
-		lastElementSaved = lastElement;
-	}
-	
-	private void end ()
+	void archiveArray (Array array, string type, string key, Id id, void delegate () dg)
 	{
-		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();
+			internalArchiveArray(array, type, key, id, Tags.arrayTag);
+			dg();
 		};
 	}
 	
-	private void archiveObject (T) (T value, DataType key, ref bool callDelegate)
-	{		
-		if (!value)
-		{
-			lastElement.element(Tags.nullTag)
-			.attribute(Attributes.typeAttribute, toDataType(T.stringof))
-			.attribute(Attributes.keyAttribute, key);
-			callDelegate = false;
-		}
-		
-		else if (auto reference = getArchivedReference(value))
-		{
-			archiveReference(key, reference);
-			callDelegate = false;
-		}
-		
-		else
-		{
-			DataType id = nextId;
-			
-			lastElement = lastElement.element(Tags.objectTag)
-			.attribute(Attributes.runtimeTypeAttribute, toDataType(value.classinfo.name))
-			.attribute(Attributes.typeAttribute, toDataType(T.stringof))
-			.attribute(Attributes.keyAttribute, key)
-			.attribute(Attributes.idAttribute, id);
-			
-			addArchivedReference(value, id);
-		}
-	}
-
-	private void archiveStruct (T) (T value, DataType key)
+	private void internalArchiveArray(Array array, string type, string key, Id id, Data tag, Data content = null)
 	{
-		lastElement = lastElement.element(Tags.structTag)
-		.attribute(Attributes.typeAttribute, toDataType(T.stringof))
-		.attribute(Attributes.keyAttribute, key);
-	}
-	
-	private void archiveString (T) (T value, DataType key)
-	{		
-		archiveArrayImpl(value, key, Tags.stringTag, toDataType(value));
-	}
-
-	private void archiveArray (T) (T value, DataType key)
-	{
-		archiveArrayImpl(value, key, Tags.arrayTag);
-	}
-	
-	private void archiveArrayImpl (T) (T value, DataType key, DataType tag, DataType content = null)
-	{
-		DataType id = nextId;
 		auto parent = lastElement;
 		
-		if (value.length == 0)
+		if (array.length == 0)
 			lastElement = lastElement.element(tag);
 		
 		else
 			lastElement = doc.createNode(tag, content);			
 		
-		lastElement.attribute(Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof))
-		.attribute(Attributes.lengthAttribute, toDataType(value.length))
-		.attribute(Attributes.keyAttribute, key)
-		.attribute(Attributes.idAttribute, id);
-
-		arraysToBeArchived[Array(value)] = ArrayNode(parent, lastElement, id, key);
+		lastElement.attribute(Attributes.typeAttribute, toData(type))
+		.attribute(Attributes.lengthAttribute, toData(array.length))
+		.attribute(Attributes.keyAttribute, toData(key))
+		.attribute(Attributes.idAttribute, toData(id));
+		
+		addArchivedArray(id, parent, lastElement, key);
+	}
+	
+	void archiveAssociativeArray (string keyType, string valueType, size_t length, string key, Id id, void delegate () dg)
+	{
+		restore(lastElement) in {
+			lastElement = lastElement.element(Tags.associativeArrayTag)		
+			.attribute(Attributes.keyTypeAttribute, toData(keyType))
+			.attribute(Attributes.valueTypeAttribute, toData(valueType))
+			.attribute(Attributes.lengthAttribute, toData(length))
+			.attribute(Attributes.keyAttribute, key)
+			.attribute(Attributes.idAttribute, toData(id));
+			
+			dg();
+		};		
+	}
+	
+	void archiveAssociativeArrayKey (string key, void delegate () dg)
+	{
+		internalArchiveAAKeyValue(key, Tags.keyTag, dg);
+	}
+	
+	void archiveAssociativeArrayValue (string key, void delegate () dg)
+	{
+		internalArchiveAAKeyValue(key, Tags.valueTag, dg);
+	}
+	
+	private void internalArchiveAAKeyValue (string key, Data tag, void delegate () dg)
+	{
+		restore(lastElement) in {
+			lastElement = lastElement.element(tag)
+			.attribute(Attributes.keyAttribute, toData(key));
+			
+			dg();
+		};
+	}
+	
+	void archiveEnum (bool value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
 	}
 
-	private void archiveAssociativeArray (T) (T value, DataType key)
+	void archiveEnum (byte value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
+	}
+
+	void archiveEnum (char value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
+	}
+
+	void archiveEnum (dchar value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
+	}
+
+	void archiveEnum (int value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
+	}
+
+	void archiveEnum (long value, string type, string key, Id id)
 	{
-		lastElement = lastElement.element(Tags.associativeArrayTag)		
-		.attribute(Attributes.keyTypeAttribute, toDataType(KeyTypeOfAssociativeArray!(T).stringof))
-		.attribute(Attributes.valueTypeAttribute, toDataType(ValueTypeOfAssociativeArray!(T).stringof))
-		.attribute(Attributes.lengthAttribute, toDataType(value.length))
-		.attribute(Attributes.keyAttribute, key);
+		internalArchiveEnum(value, type, key, id);
+	}
+
+	void archiveEnum (short value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
+	}
+
+	void archiveEnum (ubyte value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
+	}
+
+	void archiveEnum (uint value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
+	}
+
+	void archiveEnum (ulong value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
 	}
 
-	private void archivePointer (T) (T value, DataType key, ref bool callDelegate)
+	void archiveEnum (ushort value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
+	}
+
+	void archiveEnum (wchar value, string type, string key, Id id)
+	{
+		internalArchiveEnum(value, type, key, id);
+	}
+	
+	private void internalArchiveEnum (T) (T value, string type, string key, Id id)
+	{
+		lastElement.element(Tags.enumTag, toData(value))
+		.attribute(Attributes.typeAttribute, toData(type))
+		.attribute(Attributes.baseTypeAttribute, toData(T.stringof))
+		.attribute(Attributes.keyAttribute, toData(key))
+		.attribute(Attributes.idAttribute, toData(id));
+	}
+	
+	void archiveBaseClass (string type, string key, Id id)
+	{
+		restore(lastElement) in {
+			lastElement = lastElement.element(Tags.baseTag)
+			.attribute(Attributes.typeAttribute, toData(type))
+			.attribute(Attributes.keyAttribute, toData(key))
+			.attribute(Attributes.idAttribute, toData(id)); 
+		};
+	}
+	
+	void archiveNull (string type, string key)
 	{
-		if (auto reference = getArchivedReference(value))
+		lastElement.element(Tags.nullTag)
+		.attribute(Attributes.typeAttribute, toData(type))
+		.attribute(Attributes.keyAttribute, toData(key));
+	}
+	
+	void archiveObject (string runtimeType, string type, string key, Id id, void delegate () dg)
+	{
+		restore(lastElement) in {
+			lastElement = lastElement.element(Tags.objectTag)
+			.attribute(Attributes.runtimeTypeAttribute, toData(runtimeType))
+			.attribute(Attributes.typeAttribute, toData(type))
+			.attribute(Attributes.keyAttribute, toData(key))
+			.attribute(Attributes.idAttribute, toData(id));
+			
+			dg();
+		};
+	}
+	
+	void archivePointer (string key, Id id, void delegate () dg)
+	{
+		restore(lastElement) in {
+			auto parent = lastElement;
+			lastElement = doc.createNode(Tags.pointerTag);
+			
+			lastElement.attribute(Attributes.keyAttribute, toData(key))
+			.attribute(Attributes.idAttribute, toData(id));
+			
+			addArchivedPointer(id, parent, lastElement, key);			
+			dg();
+		};
+	}
+	
+	void archivePointer (Id pointeeId, string key, Id id)
+	{
+		if (auto pointerNode = getArchivedPointer(id))
 		{
-			archiveReference(key, reference);
-			callDelegate = false;
+			pointerNode.parent.element(Tags.pointerTag)
+			.attribute(Attributes.keyAttribute, toData(pointerNode.key))
+			.attribute(Attributes.idAttribute, toData(id))
+			.element(Tags.referenceTag, toData(pointeeId))
+			.attribute(Attributes.keyAttribute, toData(key));
 		}
-		
-		else
+	}
+	
+	void archiveReference (string key, Id id)
+	{
+		lastElement.element(Tags.referenceTag, toData(id))
+		.attribute(Attributes.keyAttribute, toData(key));
+	}
+
+	void archiveSlice (Slice slice, Id sliceId, Id arrayId)
+	{
+		if (auto sliceNode = getArchivedArray(sliceId))
 		{
-			DataType id = nextId;
-			
-			lastElement = lastElement.element(Tags.pointerTag)
-			.attribute(Attributes.keyAttribute, key)
-			.attribute(Attributes.idAttribute, id);
-			
-			addArchivedReference(value, id);
+			if (auto arrayNode = getArchivedArray(arrayId))
+			{
+				sliceNode.parent.element(Tags.sliceTag, toData(arrayNode.id))
+				.attribute(Attributes.keyAttribute, toData(sliceNode.key))
+				.attribute(Attributes.offsetAttribute, toData(slice.offset))
+				.attribute(Attributes.lengthAttribute, toData(slice.length));
+			}
 		}
 	}
 	
-	private void archiveEnum (T) (T value, DataType key)
+	void archiveStruct (string type, string key, Id id, void delegate () dg)
 	{
-		lastElement.element(Tags.enumTag, toDataType(value))
-		.attribute(Attributes.typeAttribute, toDataType(T.stringof))
-		.attribute(Attributes.keyAttribute, key);
+		restore(lastElement) in {
+			lastElement = lastElement.element(Tags.structTag)
+			.attribute(Attributes.typeAttribute, toData(type))
+			.attribute(Attributes.keyAttribute, toData(key))
+			.attribute(Attributes.idAttribute, toData(id));
+			
+			dg();
+		};
 	}
-
-	private void archivePrimitive (T) (T value, DataType key)
+	
+	void archiveTypedef (string type, string key, Id id, void delegate () dg)
 	{
-		lastElement.element(toDataType(T.stringof), toDataType(value))
-		.attribute(Attributes.keyAttribute, key);
+		restore(lastElement) in {
+			lastElement = lastElement.element(Tags.typedefTag)
+			.attribute(Attributes.typeAttribute, toData(type))
+			.attribute(Attributes.keyAttribute, toData(key))
+			.attribute(Attributes.idAttribute, toData(id));
+			
+			dg();
+		};
 	}
 	
-	private void archiveTypeDef (T) (T value, DataType key)
+	void archive (string value, string key, Id id)
+	{
+		archiveString(value, key, id);
+	}
+	
+	void archive (wstring value, string key, Id id)
+	{
+		archiveString(value, key, id);
+	}
+	
+	void archive (dstring value, string key, Id id)
 	{
-		lastElement = lastElement.element(Tags.typedefTag)
-		.attribute(Attributes.typeAttribute, toDataType(BaseTypeOfTypeDef!(T).stringof));
-		.attribute(Attributes.key, key);
+		archiveString(value, key, id);
+	}
+	
+	private void archiveString (T) (T value, string key, Id id)
+	{
+		restore(lastElement) in {
+			alias ElementTypeOfArray!(T) ElementType;
+			auto array = Array(value.ptr, value.length, ElementType.sizeof);
+			
+			internalArchiveArray(array, ElementType.stringof, key, id, Tags.stringTag, toData(value));
+		};
 	}
 	
-	public T unarchive (T) (DataType key, T delegate (T) dg = null)
+	void archive (bool value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+
+	void archive (byte value, string key, Id id)
 	{
-		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);				
+		archivePrimitive(value, key, id);
+	}
+
+	//currently not suppported by to!()
+	/*void archive (cdouble value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}*/
+
+	//currently not implemented but a reserved keyword
+	/*void archive (cent value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}*/
 
-			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, callDelegate);
+	//currently not suppported by to!()
+	/*void archive (cfloat value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}*/
 
-			else static if (isAssociativeArray!(T))
-				value = unarchiveAssociativeArray!(T)(key);
-
-			else static if (isPrimitive!(T))
-				value = unarchivePrimitive!(T)(key);
+	void archive (char value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
 
-			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.`));
+	//currently not suppported by to!()
+	/*void archive (creal value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}*/
 
-			if (callDelegate && dg)
-				return dg(value);
-			
-			return value;
-		};
+	void archive (dchar value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+
+	void archive (double value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+
+	void archive (float value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
 	}
 
-	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);
+	//currently not suppported by to!()
+	/*void archive (idouble value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}*/
+
+	//currently not suppported by to!()
+	/*void archive (ifloat value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}*/
+
+	void archive (int value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+
+	//currently not suppported by to!()
+	/*void archive (ireal value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}*/
+
+	void archive (long value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
 
-		if (!tmp.isValid)
-		{
-			lastElement = getElement(Tags.nullTag, key);
-			callDelegate = false;
-			return null;
-		}
-	
-		lastElement = tmp;
-		
-		auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute);
-		
-		if (!runtimeType)
-			return T.init;	
-		
-		auto name = fromDataType!(string)(runtimeType);
-		id = getValueOfAttribute(Attributes.idAttribute);
-		
-		if (!id)
-			return T.init;
-				
-		T result = cast(T) newInstance(name);
-		
-		addUnarchivedReference(result, id);
-		
-		return result;
+	void archive (real value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+
+	void archive (short value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+
+	void archive (ubyte value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+
+	//currently not implemented but a reserved keyword
+	/*void archive (ucent value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}*/
+
+	void archive (uint value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+
+	void archive (ulong value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+
+	void archive (ushort value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
 	}
 
-	private T unarchiveStruct (T) (DataType key)
+	void archive (wchar value, string key, Id id)
+	{
+		archivePrimitive(value, key, id);
+	}
+	
+	private void archivePrimitive (T) (T value, string key, Id id)
+	{
+		lastElement.element(toData(T.stringof), toData(value))
+		.attribute(Attributes.keyAttribute, toData(key))
+		.attribute(Attributes.idAttribute, toData(id));
+	}
+	
+	Id unarchiveArray (string key, void delegate (size_t) dg)
+	{
+		return restore!(Id)(lastElement) in {			
+			auto element = getElement(Tags.arrayTag, key);
+
+			if (!element.isValid)
+				return Id.max;
+
+			lastElement = element;
+			auto len = getValueOfAttribute(Attributes.lengthAttribute);
+
+			if (!len)
+				return Id.max;
+
+			auto length = fromData!(size_t)(len);
+			auto id = getValueOfAttribute(Attributes.idAttribute);	
+
+			if (!id)
+				return Id.max;
+
+			dg(length);
+			
+			return toId(id);
+		};
+	}
+	
+	void unarchiveArray (Id id, void delegate (size_t) dg)
 	{
-		auto element = getElement(Tags.structTag, key);
-		
-		if (element.isValid)
+		restore(lastElement) in {			
+			auto element = getElement(Tags.arrayTag, to!(string)(id), Attributes.idAttribute);
+			
+			if (!element.isValid)
+				return;
+	
 			lastElement = element;
-		
-		return T.init;
+			auto len = getValueOfAttribute(Attributes.lengthAttribute);
+			
+			if (!len)
+				return;
+			
+			auto length = fromData!(size_t)(len);
+			auto stringId = getValueOfAttribute(Attributes.idAttribute);	
+			
+			if (!stringId)
+				return;
+			
+			dg(length);
+		};
+	}
+	
+	Id unarchiveAssociativeArray (string key, void delegate (size_t length) dg)
+	{
+		return restore!(Id)(lastElement) in {
+			auto element = getElement(Tags.associativeArrayTag, key);
+			
+			if (!element.isValid)
+				return Id.max;
+			
+			lastElement = element;			
+			auto len = getValueOfAttribute(Attributes.lengthAttribute);
+			
+			if (!len)
+				return Id.max;
+			
+			auto length = fromData!(size_t)(len);
+			auto id = getValueOfAttribute(Attributes.idAttribute);
+			
+			if (!id)
+				return Id.max;
+			
+			dg(length);
+			
+			return toId(id);
+		};
 	}
 	
-	private T unarchiveString (T) (DataType key)
+	void unarchiveAssociativeArrayKey (string key, void delegate () dg)
 	{
-		auto slice = unarchiveSlice(key);
-		
-		if (auto tmp = getUnarchivedSlice!(T)(slice))
-			return *tmp;
-		
-		auto element = getElement(Tags.stringTag, key);
-		
-		if (!element.isValid)
-			return T.init;			
-			
-		auto value = fromDataType!(T)(element.value);
-		slice.id = getValueOfAttribute(Attributes.idAttribute, element);
-		
-		if (!slice.id)
-			return T.init;
-		
-		addUnarchivedSlice(value, slice.id);
-		
-		return value;
+		internalUnarchiveAAKeyValue(key, Tags.keyTag, dg);
+	}
+	
+	void unarchiveAssociativeArrayValue (string key, void delegate () dg)
+	{
+		internalUnarchiveAAKeyValue(key, Tags.valueTag, dg);
 	}
-
-	private T unarchiveArray (T) (DataType key, ref bool callDelegate)
-	{		
-		auto slice = unarchiveSlice(key);
-
-		if (auto tmp = getUnarchivedSlice!(T)(slice))
-		{
-			callDelegate = false;
-			return *tmp;
-		}
-		
-		T value;
-		
-		auto element = getElement(Tags.arrayTag, key);
-		
-		if (!element.isValid)
-			return T.init;
-		
-		lastElement = element;
-		auto length = getValueOfAttribute(Attributes.lengthAttribute);
-		
-		if (!length)
-			return T.init;
-		
-		value.length = fromDataType!(size_t)(length);
-		slice.id = getValueOfAttribute(Attributes.idAttribute);	
-		
-		if (!slice.id)
-			return T.init;
-		
-		addUnarchivedSlice(value, slice.id);
-		
-		return value;
+	
+	private void internalUnarchiveAAKeyValue (string key, Data tag, void delegate () dg)
+	{
+		restore(lastElement) in {
+			auto element = getElement(tag, key);
+			
+			if (!element.isValid)
+				return;
+			
+			lastElement = element;
+			
+			dg();
+		};
 	}
-
-	private T unarchiveAssociativeArray (T) (DataType key)
-	{		
-		auto element = getElement(Tags.associativeArrayTag, key);
-		
-		if (element.isValid)		
-			lastElement = element;
-		
-		return T.init;
+	
+	bool unarchiveEnumBool (string key)
+	{
+		return unarchiveEnum!(bool)(key);
 	}
-
-	private T unarchivePointer (T) (DataType key, ref bool callDelegate)
+	
+	byte unarchiveEnumByte (string key)
 	{
-		DataType id = unarchiveReference(key);
-		
-		if (auto reference = getUnarchivedReference!(T)(id))
-		{
-			callDelegate = false;
-			return *reference;
-		}
-		
-		auto element = getElement(Tags.pointerTag, key);
-		
-		if (!element.isValid)
-			return T.init;
-
-		lastElement = element; 
-		id = getValueOfAttribute(Attributes.idAttribute);
-		
-		if (!id)
-			return T.init;
-				
-		T result = new BaseTypeOfPointer!(T);
-		
-		addUnarchivedReference(result, id);
-		
-		return result;
+		return unarchiveEnum!(byte)(key);
+	}
+	
+	char unarchiveEnumChar (string key)
+	{
+		return unarchiveEnum!(char)(key);
+	}
+	
+	dchar unarchiveEnumDchar (string key)
+	{
+		return unarchiveEnum!(dchar)(key);
 	}
 	
-	private T unarchiveEnum (T) (DataType key)
+	int unarchiveEnumInt (string key)
+	{
+		return unarchiveEnum!(int)(key);
+	}
+	
+	long unarchiveEnumLong (string key)
+	{
+		return unarchiveEnum!(long)(key);
+	}
+	
+	short unarchiveEnumShort (string key)
+	{
+		return unarchiveEnum!(short)(key);
+	}
+	
+	ubyte unarchiveEnumUbyte (string key)
+	{
+		return unarchiveEnum!(ubyte)(key);
+	}
+	
+	uint unarchiveEnumUint (string key)
+	{
+		return unarchiveEnum!(uint)(key);
+	}
+	
+	ulong unarchiveEnumUlong (string key)
+	{
+		return unarchiveEnum!(ulong)(key);
+	}
+	
+	ushort unarchiveEnumUshort (string key)
+	{
+		return unarchiveEnum!(ushort)(key);
+	}
+	
+	wchar unarchiveEnumWchar (string key)
+	{
+		version (Tango)
+			return unarchiveEnum!(wchar)(key);
+			
+		else
+			return wchar.init;
+	}	
+	
+	private T unarchiveEnum (T) (string key)
 	{
 		auto element = getElement(Tags.enumTag, key);
 		
 		if (!element.isValid)
 			return T.init;
 		
-		return fromDataType!(T)(element.value);
+		return fromData!(T)(element.value);
 	}
+	
+	void unarchiveObject (string key, out Id id, out Object result, void delegate () dg)
+	{
+		restore(lastElement) in {
+			auto tmp = getElement(Tags.objectTag, key, Attributes.keyAttribute, false);
+
+			if (!tmp.isValid)
+			{
+				lastElement = getElement(Tags.nullTag, key);
+				return;
+			}
+
+			lastElement = tmp;
+			
+			auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute);
+
+			if (!runtimeType)
+				return;
+			
+			auto name = fromData!(string)(runtimeType);
+			auto stringId = getValueOfAttribute(Attributes.idAttribute);
+
+			if (!stringId)
+				return;
+
+			id = toId(stringId);
+			result = newInstance(name);
+			dg();
+		};
+	}
+	
+	Id unarchivePointer (string key, void delegate () dg)
+	{
+		return restore!(Id)(lastElement) in {
+			auto tmp = getElement(Tags.pointerTag, key, Attributes.keyAttribute, false);
+
+			if (!tmp.isValid)
+			{
+				lastElement = getElement(Tags.nullTag, key);
+				return Id.max;
+			}
+			
+			lastElement = tmp;
+			auto id = getValueOfAttribute(Attributes.idAttribute);
 
-	private T unarchivePrimitive (T) (DataType key)
-	{		
-		auto element = getElement(toDataType(T.stringof), key);
+			if (!id)
+				return Id.max;
+			
+			dg();
+			
+			return toId(id);
+		};
+	}
+	
+	Id unarchiveReference (string key)
+	{
+		auto element = getElement(Tags.referenceTag, key, Attributes.keyAttribute, false);
+		
+		if (element.isValid)
+			return toId(element.value);
 		
-		if (!element.isValid)
-			return T.init;
+		return Id.max;
+	}
+	
+	Slice unarchiveSlice (string key)
+	{
+		auto element = getElement(Tags.sliceTag, key, Attributes.keyAttribute, false);
+
+		if (element.isValid)
+		{
+			auto length = fromData!(size_t)(getValueOfAttribute(Attributes.lengthAttribute, element));
+			auto offset = fromData!(size_t)(getValueOfAttribute(Attributes.offsetAttribute, element));
+			auto id = toId(element.value);
+			
+			return Slice(length, offset, id);
+		}
 		
-		return fromDataType!(T)(element.value);
+		return Slice.init;
+	}
+	
+	void unarchiveStruct (string key, void delegate () dg)
+	{
+		restore(lastElement) in {
+			auto element = getElement(Tags.structTag, key);
+		
+			if (!element.isValid)
+				return;
+			
+			lastElement = element;			
+			dg();
+		};
 	}
 	
 	private T unarchiveTypeDef (T) (DataType key)
@@ -568,53 +809,258 @@
 		return T.init;
 	}
 	
-	public AssociativeArrayVisitor!(KeyTypeOfAssociativeArray!(T), ValueTypeOfAssociativeArray!(T)) unarchiveAssociativeArrayVisitor (T)  ()
+	void unarchiveTypedef (string key, void delegate () dg)
+	{
+		restore(lastElement) in {
+			auto element = getElement(Tags.typedefTag, key);
+			
+			if (!element.isValid)
+				return;
+			
+			lastElement = element;
+			dg();
+		};
+	}
+	
+	string unarchiveString (string key, out Id id)
+	{
+		return internalUnarchiveString!(string)(key, id);
+	}
+	
+	wstring unarchiveWstring (string key, out Id id)
+	{
+		return internalUnarchiveString!(wstring)(key, id);
+	}
+	
+	dstring unarchiveDstring (string key, out Id id)
 	{
-		return AssociativeArrayVisitor!(KeyTypeOfAssociativeArray!(T), ValueTypeOfAssociativeArray!(T))(this);
+		return internalUnarchiveString!(dstring)(key, id);
+	}
+	
+	private T internalUnarchiveString (T) (string key, out Id id)
+	{
+		auto element = getElement(Tags.stringTag, key);
+		
+		if (!element.isValid)
+			return T.init;
+
+		auto value = fromData!(T)(element.value);
+		auto stringId = getValueOfAttribute(Attributes.idAttribute, element);
+
+		if (!stringId)
+			return T.init;
+
+		id = toId(stringId);
+		return value;
+	}
+	
+	string unarchiveString (Id id)
+	{
+		return internalUnarchiveString!(string)(id);
+	}
+	
+	wstring unarchiveWstring (Id id)
+	{
+		return internalUnarchiveString!(wstring)(id);
 	}
 	
-	public void archiveBaseClass (T : Object) (DataType key)
+	dstring unarchiveDstring (Id id)
+	{
+		return internalUnarchiveString!(dstring)(id);
+	}
+	
+	private T internalUnarchiveString (T) (Id id)
 	{
-		lastElement = lastElement.element(Tags.baseTag)
-		.attribute(Attributes.typeAttribute, toDataType(T.stringof))
-		.attribute(Attributes.keyAttribute, key);
+		auto element = getElement(Tags.stringTag, to!(string)(id), Attributes.idAttribute);
+		
+		if (!element.isValid)
+			return T.init;
+
+		return fromData!(T)(element.value);
+	}
+	
+	bool unarchiveBool (string key)
+	{
+		return unarchivePrimitive!(bool)(key);
+	}
+	
+	byte unarchiveByte (string key)
+	{
+		return unarchivePrimitive!(byte)(key);
 	}
 	
-	public void unarchiveBaseClass (T : Object) (DataType key)
+	//currently not suppported by to!()
+    /*cdouble unarchiveCdouble (string key)
+	{
+		return unarchivePrimitive!(cdouble)(key);
+	}*/
+	 
+	 //currently not implemented but a reserved keyword
+    /*cent unarchiveCent (string key)
+	{
+		return unarchivePrimitive!(cent)(key);
+	}*/
+	
+	// currently not suppported by to!()
+    /*cfloat unarchiveCfloat (string key)
 	{
-		auto element = getElement(Tags.baseTag, key);
-		
-		if (element.isValid)
-			lastElement = element;
+		return unarchivePrimitive!(cfloat)(key);
+	}*/
+	
+	char unarchiveChar (string key)
+	{
+		return unarchivePrimitive!(char)(key);
+	}
+	 
+	 //currently not implemented but a reserved keyword
+	/*creal unarchiveCreal (string key)
+	{
+		return unarchivePrimitive!(creal)(key);
+	}*/
+	
+	dchar unarchiveDchar (string key)
+	{
+		return unarchivePrimitive!(dchar)(key);
+	}
+	
+	double unarchiveDouble (string key)
+	{
+		return unarchivePrimitive!(double)(key);
 	}
 	
-	version (Tango)
+	float unarchiveFloat (string key)
+	{
+		return unarchivePrimitive!(float)(key);
+	}
+
+	//currently not suppported by to!()
+    /*idouble unarchiveIdouble (string key)
+	{
+		return unarchivePrimitive!(idouble)(key);
+	}*/
+    
+    // currently not suppported by to!()*/
+    /*ifloat unarchiveIfloat (string key)
+	{
+		return unarchivePrimitive!(ifloat)(key);
+	}*/
+
+	int unarchiveInt (string key)
+	{
+		return unarchivePrimitive!(int)(key);
+	}
+
+	// currently not suppported by to!()
+    /*ireal unarchiveIreal (string key)
+	{
+		return unarchivePrimitive!(ireal)(key);
+	}*/
+
+	long unarchiveLong (string 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: ";
-		}
+		return unarchivePrimitive!(long)(key);
+	}
+	
+	real unarchiveReal (string key)
+	{
+		return unarchivePrimitive!(real)(key);
+	}
+	
+	short unarchiveShort (string key)
+	{
+		return unarchivePrimitive!(short)(key);
+	}
+	
+	ubyte unarchiveUbyte (string key)
+	{
+		return unarchivePrimitive!(ubyte)(key);
+	}
+
+	// currently not implemented but a reserved keyword
+    /*ucent unarchiveCcent (string key)
+	{
+		return unarchivePrimitive!(ucent)(key);
+	}*/
+
+	uint unarchiveUint (string key)
+	{
+		return unarchivePrimitive!(uint)(key);
+	}
+	
+	ulong unarchiveUlong (string key)
+	{
+		return unarchivePrimitive!(ulong)(key);
 	}
 	
-	else
+	ushort unarchiveUshort (string key)
+	{
+		return unarchivePrimitive!(ushort)(key);
+	}
+	
+	wchar unarchiveWchar (string key)
 	{
-		mixin(
-			`template errorMessage (ArchiveMode mode = ArchiveMode.archiving)
-			{
-				static if (mode == ArchiveMode.archiving)
-					enum errorMessage = "Could not continue archiving due to unrecognized data format: ";
-					
-				else static if (mode == ArchiveMode.unarchiving)
-					enum errorMessage = "Could not continue unarchiving due to unrecognized data format: ";
-			}`
-		);
+		version (Tango)
+			return unarchivePrimitive!(wchar)(key);
+			
+		else
+			return wchar.init;
+	}
+	
+	T unarchivePrimitive (T) (string key)
+	{
+		auto element = getElement(toData(T.stringof), key);
+
+		if (!element.isValid)
+			return T.init;
+		
+		return fromData!(T)(element.value);
+	}
+	
+	void postProcessArray (Id id)
+	{
+		if (auto array = getArchivedArray(id))
+			array.parent.attach(array.node);
 	}
 	
-	private doc.Node getElement (DataType tag, DataType key, DataType attribute = Attributes.keyAttribute, bool throwOnError = true)
+	void postProcessPointer (Id id)
+	{
+		if (auto pointer = getArchivedPointer(id))
+			pointer.parent.attach(pointer.node);
+	}
+	
+	private void addArchivedArray (Id id, doc.Node parent, doc.Node element, string key)
+	{
+		archivedArrays[id] = Node(parent, element, id, key);
+	}
+	
+	private Node* getArchivedArray (Id id)
+	{
+		if (auto array = id in archivedArrays)
+			return array;
+
+		if (errorCallback)
+			errorCallback(new ArchiveException(`Could not continue archiving due to no array with the Id "` ~ to!(string)(id) ~ `" was found.`, __FILE__, __LINE__), [to!(string)(id)]);
+		
+		return null;
+	}
+	
+	private void addArchivedPointer (Id id, doc.Node parent, doc.Node element, string key)
+	{
+		archivedPointers[id] = Node(parent, element, id, key);
+	}
+	
+	private Node* getArchivedPointer (Id id)
+	{
+		if (auto pointer = id in archivedPointers)
+			return pointer;
+
+		if (errorCallback)
+			errorCallback(new ArchiveException(`Could not continue archiving due to no pointer with the Id "` ~ to!(string)(id) ~ `" was found.`, __FILE__, __LINE__), [to!(string)(id)]);
+		
+		return null;
+	}
+	
+	private doc.Node getElement (Data tag, string key, Data attribute = Attributes.keyAttribute, bool throwOnError = true)
 	{		
 		auto set = lastElement.query[tag].attribute((doc.Node node) {
 			if (node.name == attribute && node.value == key)
@@ -622,7 +1068,7 @@
 			
 			return false;
 		});
-		
+
 		if (set.nodes.length == 1)
 			return set.nodes[0].parent;
 		
@@ -641,9 +1087,10 @@
 		}
 	}
 	
-	private DataType getValueOfAttribute (DataType attribute, doc.Node element = doc.Node.invalid)
+	private Data getValueOfAttribute (Data attribute, doc.Node element = doc.Node.invalid)
 	{
-		if (!element.isValid) element = lastElement;
+		if (!element.isValid)
+			element = lastElement;
 		
 		auto set = element.query.attribute(attribute);
 		
@@ -665,150 +1112,29 @@
 		return null;
 	}
 	
-	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 void addUnarchivedSlice (T) (T value, DataType id)
-	{
-		static assert(isArray!(T) || isString!(T), format!(`The given type "`, T, `" is not a slice type, i.e. array or string.`));
-
-		unarchivedSlices[id] = 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 T* getUnarchivedSlice (T) (Slice slice)
-	{
-		if (auto array = slice.id in unarchivedSlices)	
-			return &(cast(T) *array)[slice.offset .. slice.length + 1]; // dereference the array, cast it to the right type, 
-																		// slice it and then return a pointer to the result		
-		return null;
-	}
-	
-	private DataType nextId ()
+	version (Tango)
 	{
-		return toDataType(idCounter++);
-	}
-	
-	private void archiveReference (DataType key, DataType id)
-	{		
-		lastElement.element(Tags.referenceTag, id)
-		.attribute(Attributes.keyAttribute, key);
-	}
-	
-	private DataType unarchiveReference (DataType key)
-	{	
-		auto element = getElement(Tags.referenceTag, key, Attributes.keyAttribute, false);
-		
-		if (element.isValid)
-			return element.value;
-		
-		return cast(DataType) null;
-	}
-	
-	private Slice unarchiveSlice (DataType key)
-	{
-		auto element = getElement(Tags.sliceTag, key, Attributes.keyAttribute, false);
-		
-		if (element.isValid)
+		private template errorMessage (ArchiveMode mode = ArchiveMode.archiving)
 		{
-			auto length = fromDataType!(size_t)(getValueOfAttribute(Attributes.lengthAttribute, element));
-			auto offset = fromDataType!(size_t)(getValueOfAttribute(Attributes.offsetAttribute, element));
-			
-			return Slice(length, offset, element.value);
-		}
-		
-		return Slice.init;
-	}	
-	
-	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);	
-					}		
-				};
+			static if (mode == ArchiveMode.archiving)
+				const errorMessage = "Could not continue archiving due to unrecognized data format: ";
 				
-				if (result)
-					break;
-			}
-			
-			return result;
+			else static if (mode == ArchiveMode.unarchiving)
+				const errorMessage = "Could not continue unarchiving due to unrecognized data format: ";
 		}
 	}
 	
-	public void postProcess ()
+	else
 	{
-		bool foundSlice = true;
-		
-		foreach (slice, sliceNode ; arraysToBeArchived)
-		{
-			foreach (array, arrayNode ; arraysToBeArchived)
+		mixin(
+			`private template errorMessage (ArchiveMode mode = ArchiveMode.archiving)
 			{
-				if (slice.isSliceOf(array) && slice != array)
-				{
-					sliceNode.parent.element(Tags.sliceTag, arrayNode.id)
-					.attribute(Attributes.keyAttribute, sliceNode.key)
-					.attribute(Attributes.offsetAttribute, toDataType((slice.ptr - array.ptr) / slice.elementSize))
-					.attribute(Attributes.lengthAttribute, toDataType(slice.length));
+				static if (mode == ArchiveMode.archiving)
+					enum errorMessage = "Could not continue archiving due to unrecognized data format: ";
 					
-					foundSlice = true;
-					break;
-				}
-				
-				else
-					foundSlice = false;
-			}
-			
-			if (!foundSlice)
-				sliceNode.parent.attach(sliceNode.node);
-		}
-	}	
+				else static if (mode == ArchiveMode.unarchiving)
+					enum errorMessage = "Could not continue unarchiving due to unrecognized data format: ";
+			}`
+		);
+	}
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/test/UnitTester.d	Wed Aug 03 21:58:21 2011 +0200
@@ -0,0 +1,567 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Oct 17, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.test.UnitTester;
+
+version (Tango)
+{
+	import tango.core.Exception;
+	import tango.io.device.File;
+	import tango.io.FilePath;
+	import tango.io.stream.Lines;
+	import tango.sys.Environment;
+	import tango.util.Convert;
+}
+	
+
+else
+{
+	import core.exception;
+	import std.conv;
+	
+	private alias AssertError AssertException;
+}
+
+
+import orange.core._;
+import orange.util._;
+
+Use!(void delegate (), string) describe (string message)
+{
+	return UnitTester.instance.describe(message);
+}
+
+Use!(void delegate (), string) it (string message)
+{
+	return UnitTester.instance.test(message);
+}
+
+void delegate () before ()
+{
+	return UnitTester.instance.before;
+}
+
+void delegate () before (void delegate () before)
+{
+	return UnitTester.instance.before = before;
+}
+
+void delegate () after ()
+{
+	return UnitTester.instance.after;
+}
+
+void delegate () after (void delegate () after)
+{
+	return UnitTester.instance.after = after;
+}
+
+void run ()
+{
+	UnitTester.instance.run;
+}
+
+private:
+
+class UnitTester
+{	
+	private:
+		
+	struct DescriptionManager
+	{
+		Description[] descriptions;
+		size_t lastIndex = size_t.max;
+		
+		void opCatAssign (Description description)
+		{
+			descriptions ~= description;
+			lastIndex++;
+		}
+		
+		void opCatAssign (Test test)
+		{
+			last.tests ~= test;
+		}
+		
+		Description opIndex (size_t i)
+		{
+			return descriptions[i];
+		}
+		
+		Description last ()
+		{
+			return descriptions[$ - 1];
+		}
+		
+		Description first ()
+		{
+			return descriptions[0];
+		}
+		
+		int opApply (int delegate(ref Description) dg)
+		{
+			int result = 0;
+			
+			foreach (desc ; descriptions)
+			{
+				result = dg(desc);
+				
+				if (result)
+					return result;
+			}
+			
+			return result;
+		}
+		
+		size_t length ()
+		{
+			return descriptions.length;
+		}
+	}
+	
+	class Description
+	{
+		private
+		{
+			DescriptionManager descriptions;
+			Test[] tests;
+			Test[] failures;
+			Test[] pending;
+			size_t lastIndex = size_t.max;
+			string message;
+			void delegate () description;
+		}
+		
+		this (string message)
+		{
+			this.message = message;
+		}
+		
+		void run ()
+		{
+			if (shouldRun)
+				description();
+		}
+		
+		bool shouldRun ()
+		{
+			return description !is null;
+		}
+	}
+	
+	struct Test
+	{
+		void delegate () test;
+		string message;
+		AssertException exception;
+		
+		bool failed ()
+		{
+			return !succeeded;
+		}
+		
+		bool succeeded ()
+		{
+			if (exception is null)
+				return true;
+			
+			return false;
+		}
+		
+		void run ()
+		{
+			if (!isPending)
+				test();
+		}
+		
+		bool isPending ()
+		{
+			return test is null;
+		}
+	}
+	
+	static UnitTester instance_;
+	
+	DescriptionManager descriptions;
+	Description currentDescription;
+	
+	void delegate () before_;
+	void delegate () after_;
+	
+	size_t numberOfFailures;
+	size_t numberOfPending;
+	size_t numberOfTests;
+	size_t failureId;
+	
+	string defaultIndentation = "    ";
+	string indentation;
+	
+	static UnitTester instance ()
+	{
+		if (instance_)
+			return instance_;
+		
+		return instance_ = new UnitTester;
+	}
+	
+	Use!(void delegate (), string) describe (string message)
+	{
+		addDescription(message);		
+		Use!(void delegate (), string) use;
+		
+		use.args[0] = &internalDescribe;
+		use.args[1] = message;
+		
+		return use;
+	}
+	
+	Use!(void delegate (), string) test (string message)
+	{
+		addTest(message);		
+		Use!(void delegate (), string) use;
+		
+		use.args[0] = &internalTest;		
+		use.args[1] = message;
+		
+		return use;
+	}
+	
+	void run ()
+	{
+		foreach (description ; descriptions)
+			runDescription(description);
+
+		printResult;
+	}
+	
+	void runDescription (Description description)
+	{
+		restore(currentDescription) in {
+			currentDescription = description;
+			description.run;
+
+			foreach (desc ; description.descriptions)
+				runDescription(desc);
+			
+			foreach (test ; description.tests)
+			{
+				if (test.isPending)
+					addPendingTest(description, test);
+
+				try
+				{
+					execute in {
+						test.run();
+					};				
+				}				
+				
+				catch (AssertException e)
+					handleFailure(description, test, e);
+			}
+		};
+	}
+	
+	void delegate () before ()
+	{
+		return before_;
+	}
+	
+	void delegate () before (void delegate () before)
+	{
+		return before_ = before;
+	}
+	
+	void delegate () after ()
+	{
+		return after_;
+	}
+
+	void delegate () after (void delegate () after)
+	{
+		return after_ = after;
+	}
+	
+	void addTest (string message)
+	{
+		numberOfTests++;
+		currentDescription.tests ~= Test(null, message);
+	}
+	
+	void addDescription (string message)
+	{
+		if (currentDescription)
+			currentDescription.descriptions ~= new Description(message);
+		
+		else
+			descriptions ~= new Description(message);
+	}
+	
+	void addPendingTest (Description description, ref Test test)
+	{
+		numberOfPending++;
+		description.pending ~= test;
+	}
+	
+	void handleFailure (Description description, ref Test test, AssertException exception)
+	{
+		numberOfFailures++;
+		test.exception = exception;
+		description.failures ~= test;
+	}
+	
+	void internalDescribe (void delegate () dg, string message)
+	{
+		if (currentDescription)
+			currentDescription.descriptions.last.description = dg;
+		
+		else
+			descriptions.last.description = dg;
+	}
+	
+	void internalTest (void delegate () dg, string message)
+	{
+		currentDescription.tests[$ - 1] = Test(dg, message);
+	}
+	
+	void printResult ()
+	{	
+		if (isAllTestsSuccessful)
+			return printSuccess();
+		
+		foreach (description ; descriptions)
+		{
+			printDescription(description);
+			printResultImpl(description.descriptions);
+		}
+		
+		failureId = 0;
+		
+		printPending;		
+		printFailures;
+
+		print("\n", numberOfTests, " ", pluralize("test", numberOfTests),", ", numberOfFailures, " ", pluralize("failure", numberOfFailures));
+		printNumberOfPending;
+		println();
+	}
+	
+	void printResultImpl (DescriptionManager descriptions)
+	{
+		restore(indentation) in {
+			indentation ~= defaultIndentation;
+			
+			foreach (description ; descriptions)
+			{
+				printDescription(description);
+				printResultImpl(description.descriptions);
+			}
+		};
+	}
+	
+	void printDescription (Description description)
+	{
+		println(indentation, description.message);
+
+		restore(indentation) in {
+			indentation ~= defaultIndentation;
+
+			foreach (i, ref test ; description.tests)
+			{
+				print(indentation, "- ", test.message);
+				
+				if (test.isPending)
+					print(" (PENDING: Not Yet Implemented)");
+				
+				if (test.failed)
+					print(" (FAILED - ", ++failureId, ')');
+				
+				println();
+			}
+		};
+	}
+	
+	void printPending ()
+	{
+		if (!hasPending)
+			return;
+		
+		println("\nPending:");
+
+		restore(indentation) in {
+			indentation ~= defaultIndentation;
+			
+			foreach (description ; descriptions)
+			{
+				printPendingDescription(description);
+				printPendingImpl(description.descriptions);
+			}
+		};
+	}
+	
+	void printPendingImpl (DescriptionManager descriptions)
+	{
+		foreach (description ; descriptions)
+		{
+			printPendingDescription(description);
+			printPendingImpl(description.descriptions);
+		}
+	}
+	
+	void printPendingDescription (Description description)
+	{
+		foreach (test ; description.pending)
+			println(indentation, description.message, " ", test.message, "\n", indentation, indentation, "# Not Yet Implemented");
+	}
+	
+	void printFailures ()
+	{
+		if (!hasFailures)
+			return;
+		
+		println("\nFailures:");
+
+		restore(indentation) in {
+			indentation ~= defaultIndentation;
+			
+			foreach (description ; descriptions)
+			{
+				printFailuresDescription(description);
+				printFailuresImpl(description.descriptions);
+			}
+		};
+	}
+	
+	void printFailuresImpl (DescriptionManager descriptions)
+	{
+		foreach (description ; descriptions)
+		{
+			printFailuresDescription(description);
+			printFailuresImpl(description.descriptions);
+		}
+	}
+	
+	void printFailuresDescription (Description description)
+	{
+		foreach (test ; description.failures)
+		{
+			auto str = indentation ~ to!(string)(++failureId) ~ ") ";
+			auto whitespace = toWhitespace(str.length);
+			
+			println(str, description.message, " ", test.message);			
+			println(whitespace, "# ", test.exception.file, ".d:", test.exception.line);
+			println(whitespace, "Stack trace:");
+			print(whitespace);
+			
+			version (Tango)
+			{
+				test.exception.writeOut(&printStackTrace);
+				println();
+				println(readFailedTest(test));
+			}				
+		}
+	}
+	
+	void printStackTrace (string str)
+	{
+		return print(str);
+		
+		/*if (str.find("start") < size_t.max ||
+		    str.find("main") < size_t.max ||
+		    str.find("rt.compiler.") < size_t.max ||
+		    str.find("orange.") ||
+		    str.find(":0") ||
+		    str.find("_d_assert") ||
+		    str.find("onAssertError") ||
+		    str.find("tango.core.Exception.AssertException._ctor ") ||
+		    str.find("object.") ||
+		    str.find("tango.core.tools."))
+				return;*/
+	}
+
+	version (Tango)
+	{
+		string readFailedTest (ref Test test, int numberOfSurroundingLines = 3)
+		{		
+			auto filename = test.exception.file.dup.replace('.', '/');
+
+			filename ~= ".d";
+			filename = Environment.toAbsolute(filename);
+			auto lineNumber = test.exception.line;
+			string str;
+			auto file = new File(filename);		
+
+			foreach (i, line ; new Lines!(char)(file))			
+				if (i >= (lineNumber - 1) - numberOfSurroundingLines && i <= (lineNumber - 1) + numberOfSurroundingLines)
+					str ~= line ~ '\n';
+
+			file.close;
+
+			return str;
+		}
+	}
+	
+	void printNumberOfPending ()
+	{
+		if (hasPending)
+			print(", ", numberOfPending, " pending");
+	}
+	
+	void printSuccess ()
+	{
+		println("All ", numberOfTests, pluralize(" test", numberOfTests), " passed successfully.");
+	}
+	
+	bool isAllTestsSuccessful ()
+	{
+		return !hasPending && !hasFailures;
+	}
+	
+	bool hasPending ()
+	{
+		return numberOfPending > 0;
+	}
+	
+	bool hasFailures ()
+	{
+		return numberOfFailures > 0;
+	}
+	
+	Use!(void delegate ()) execute ()
+	{
+		Use!(void delegate ()) use;
+		
+		use.args[0] = &executeImpl;
+		
+		return use;
+	}
+	
+	void executeImpl (void delegate () dg)
+	{
+		auto before = this.before;
+		auto after = this.after;
+		
+		if (before) before();
+		if (dg) dg();
+		if (after) after();
+	}
+	
+	string toWhitespace (size_t value)
+	{
+		string str;
+		
+		for (size_t i = 0; i < value; i++)
+			str ~= ' ';
+		
+		return str;
+	}
+	
+	string pluralize (string str, int value)
+	{
+		if (value == 1)
+			return str;
+		
+		return str ~ "s";
+	}
+}
\ No newline at end of file
--- a/orange/util/CTFE.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/util/CTFE.d	Wed Aug 03 21:58:21 2011 +0200
@@ -6,7 +6,7 @@
  */
 module orange.util.CTFE;
 
-import orange.util.string;
+import orange.core.string;
 import orange.util.Traits;
 
 template format (ARGS...)
@@ -101,7 +101,7 @@
  */
 bool contains (T) (T[] arr, T element)
 {
-	return arr.indexOf(element) != size_t.max;
+	return indexOf(arr, element) != size_t.max;
 }
 
 /**
--- a/orange/util/Reflection.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/util/Reflection.d	Wed Aug 03 21:58:21 2011 +0200
@@ -6,8 +6,8 @@
  */
 module orange.util.Reflection;
 
+import orange.core.string;
 import orange.util.CTFE;
-import orange.util.string;
 
 /**
  * Returns the name of the given function
--- a/orange/util/Traits.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/util/Traits.d	Wed Aug 03 21:58:21 2011 +0200
@@ -28,6 +28,8 @@
 	version = Phobos;
 }
 
+import orange.core.string;
+
 template isPrimitive (T)
 {
 	const bool isPrimitive = is(T == bool) ||
@@ -91,7 +93,7 @@
 
 template isString (T)
 {
-	const bool isString = is(T : char[]) || is(T : wchar[]) || is(T : dchar[]);
+	const bool isString = is(T : string) || is(T : wstring) || is(T : dstring);
 }
 
 template isAssociativeArray (T)
@@ -123,9 +125,9 @@
 	const bool isReference = isObject!(T) || isPointer!(T);
 }
 
-template isTypeDef (T)
+template isTypedef (T)
 {
-	const bool isTypeDef = is(T == typedef);
+	const bool isTypedef = is(T == typedef);
 }
 
 template isVoid (T)
@@ -133,13 +135,9 @@
 	const bool isVoid = is(T == void);
 }
 
-template BaseTypeOfArray (T)
+template ElementTypeOfArray(T : T[])
 {
-	static if (is(T U : U[]))
-		alias BaseTypeOfArray!(U) BaseTypeOfArray;
-	
-	else
-		alias T BaseTypeOfArray;
+	alias T ElementTypeOfArray;
 }
 
 template BaseTypeOfPointer (T)
@@ -151,13 +149,22 @@
 		alias T BaseTypeOfPointer;
 }
 
-template BaseTypeOfTypeDef (T)
+template BaseTypeOfTypedef (T)
 {
 	static if (is(T U == typedef))
-		alias BaseTypeOfTypeDef!(U) BaseTypeOfTypeDef;
+		alias BaseTypeOfTypedef!(U) BaseTypeOfTypedef;
 	
 	else
-		alias T BaseTypeOfTypeDef;
+		alias T BaseTypeOfTypedef;
+}
+
+template BaseTypeOfEnum (T)
+{
+	static if (is(T U == enum))
+		alias BaseTypeOfEnum!(U) BaseTypeOfEnum;
+	
+	else
+		alias T BaseTypeOfEnum;
 }
 
 template KeyTypeOfAssociativeArray (T)
--- a/orange/util/Use.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/util/Use.d	Wed Aug 03 21:58:21 2011 +0200
@@ -15,13 +15,14 @@
 else
 {
 	import std.typetuple;
+	import std.typecons;
 	import std.traits;
 	
 	alias ReturnType ReturnTypeOf;
 	alias ParameterTypeTuple ParameterTupleOf;
 }
 
-struct OpInStruct (ARGS...)
+struct Use (ARGS...)
 {
 	static assert (ARGS.length > 0);
 	
@@ -46,7 +47,13 @@
 			return args[0](dg);
 			
 		else
-			return args[0](dg, args[1 .. $]);
+		{
+			version (Tango)
+				return args[0](dg, args[1 .. $]);
+			
+			else
+				return args[0](dg, args.expand[1 .. $]);
+		}
 	}
 }
 
--- a/orange/util/_.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/util/_.d	Wed Aug 03 21:58:21 2011 +0200
@@ -9,8 +9,6 @@
 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
--- a/orange/util/collection/Array.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/util/collection/Array.d	Wed Aug 03 21:58:21 2011 +0200
@@ -19,7 +19,11 @@
 	version = Phobos;
 	
 	import std.c.string : memmove;
-}	
+	import algorithm = std.algorithm;
+}
+
+import orange.core.string;
+import orange.util.Traits;
 
 /**
  * Inserts the specified element at the specified position in the array. Shifts the
@@ -276,6 +280,36 @@
 }
 
 /**
+ * Returns $(D_KEYWORD true) if the array contains the given pattern.
+ * 
+ * Params:
+ *     arr = the array to check if it contains the element
+ *     pattern = the pattern whose presence in the array is to be tested
+ *     
+ * Returns: $(D_KEYWORD true) if the array contains the given pattern
+ */
+bool contains (T) (T[] arr, T[] pattern)
+{
+	static if (isChar!(T))
+	{
+		version (Tango)
+			return tango.text.Util.containsPattern(arr, pattern);
+		
+		else
+			return stdString.indexOf(arr, element) != -1;
+	}
+	
+	else
+	{
+		version (Tango)
+			return tango.core.Array.contains(arr, pattern);
+		
+		else
+			return !algorithm.find(arr, pattern).empty;
+	}
+}
+
+/**
  * Returns $(D_KEYWORD true) if this array contains no elements.
  * 
  * Params:
@@ -433,7 +467,7 @@
  * 
  * Returns: the array
  */
-T[] replace (T, U = size_t) (ref T[] arr, U pos, U n, T[] elements)
+/*T[] replace (T, U = size_t) (ref T[] arr, U pos, U n, T[] elements)
 in
 {
 	assert(pos <= arr.length, "mambo.collection.Array.replace: The position was greter than the length of the array");
@@ -491,9 +525,54 @@
 	}
 	
 	return arr;
+}*/
+
+/**
+ * Replaces all the occurences of $(D_PARAM pattern) with $(D_PARAM replacement)
+ * 
+ * Params:
+ *     arr = the array to do the raplce in
+ *     pattern = the pattern to match
+ *     replacement = the values to subsitute
+ *     
+ * Returns: the passed in array with all the patterns subsituted
+ */
+T[] replace (T : wchar) (T[] arr, dchar pattern, dchar replacement)
+{
+	foreach (i, dchar e ; arr)
+		if (e == pattern)
+			arr[i] = replacement;
+	
+	return arr;
 }
 
 /**
+ * Replaces all the occurences of $(D_PARAM pattern) with $(D_PARAM replacement)
+ * 
+ * Params:
+ *     arr = the array to do the raplce in
+ *     pattern = the pattern to match
+ *     replacement = the values to subsitute
+ *     
+ * Returns: the passed in array with all the patterns subsituted
+ */
+/*T[] replace (T) (T[] arr, T pattern, T replacement)
+{
+	version (Tango)
+		tango.core.Array.replace(arr, pattern, replacement);
+	
+	
+	else
+	{
+		foreach (ref e ; arr)
+			if (e == pattern)
+				e = replacement;
+	}
+	
+	return arr;
+}*/
+
+/**
  * Erases a part of the array content, shortening the length of the array.
  * 
  * Params:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/util/collection/_.d	Wed Aug 03 21:58:21 2011 +0200
@@ -0,0 +1,11 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Nov 21, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module orange.util.collection._;
+
+public:
+	
+import orange.util.collection.Array;
\ No newline at end of file
--- a/orange/util/io.d	Mon Oct 04 20:45:32 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/**
- * Copyright: Copyright (c) 2007-2008 Jacob Carlborg. All rights reserved.
- * Authors: Jacob Carlborg
- * Version: Initial created: 2007
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
- * 
- */
-module orange.util.io;
-
-version (Tango)
-{
-	import tango.io.Stdout;
-	import tango.io.Console;
-	
-	import orange.util.string;
-}
-
-else 
-	import std.stdio;
-
-/**
- * Print to the standard output
- * 
- * Params:
- *     args = what to print
- */
-void print (A...)(A args)
-{
-	version (Tango)
-	{
-		const string fmt = "{}{}{}{}{}{}{}{}"
-					        "{}{}{}{}{}{}{}{}"
-					        "{}{}{}{}{}{}{}{}";
-				
-		static assert (A.length <= fmt.length / 2, "mambo.io.print :: too many arguments");
-		
-		Stdout.format(fmt[0 .. args.length * 2], args).flush;
-	}
-		
-	
-	else
-		write(args);
-}
-
-/**
- * Print to the standard output, adds a new line
- * 
- * Params:
- *     args = what to print
- */
-void println (A...)(A args)
-{
-	version (Tango)
-	{
-		const string fmt = "{}{}{}{}{}{}{}{}"
-					        "{}{}{}{}{}{}{}{}"
-					        "{}{}{}{}{}{}{}{}";
-
-		static assert (A.length <= fmt.length / 2, "mambo.io.println :: too many arguments");
-		
-		Stdout.formatln(fmt[0 .. args.length * 2], args);
-	}
-
-	else
-		writeln(args);
-}
\ No newline at end of file
--- a/orange/util/string.d	Mon Oct 04 20:45:32 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,888 +0,0 @@
-/**
- * Copyright: Copyright (c) 2008-2009 Jacob Carlborg. All rights reserved.
- * Authors: Jacob Carlborg
- * Version: Initial created: 2008
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
- * 
- */
-module orange.util.string;
-
-public import orange.util.collection.Array;
-
-version (Tango)
-{
-	static import tango.stdc.stringz;
-	import tango.text.Unicode : toFold, isDigit;
-	import tango.text.convert.Utf;
-	import tango.text.Util;
-	
-	alias tango.stdc.stringz.toStringz toStringz;
-	alias tango.stdc.stringz.toString16z toString16z;
-	alias tango.stdc.stringz.toString32z toString32z;
-	
-	alias tango.stdc.stringz.fromStringz fromStringz;
-	alias tango.stdc.stringz.fromString16z fromString16z;
-	alias tango.stdc.stringz.fromString32z fromString32z;
-	
-	alias tango.text.convert.Utf.toString16 toString16;
-	alias tango.text.convert.Utf.toString32 toString32;
-}
-
-else
-{	
-	import std.string;
-	import std.utf;
-	import std.ctype : isxdigit;
-	
-	version = Phobos;
-	
-	private alias std.string.tolower toFold;
-	
-	alias std.utf.toUTF8 toString;
-	alias std.utf.toUTF16 toString16;
-	alias std.utf.toUTF32 toString32;
-	
-	alias std.string.toStringz toStringz;
-	alias std.utf.toUTF16z toString16z;
-	
-	alias std.string.toString fromStringz;
-}
-
-version (Tango)
-{
-	/**
-	 * string alias
-	 */
-	alias char[] string;
-
-	/**
-	 * wstring alias
-	 */
-	alias wchar[] wstring;
-
-	/**
-	 * dstring alias
-	 */
-	alias dchar[] dstring;
-}
-
-/**
- * Compares the $(D_PSYMBOL string) to another $(D_PSYMBOL string), ignoring case
- * considerations.  Two strings are considered equal ignoring case if they are of the
- * same length and corresponding characters in the two strings  are equal ignoring case.
- * 
- * Params:
- *     str = The $(D_PSYMBOL string) first string to compare to
- *     anotherString = The $(D_PSYMBOL string) to compare the first $(D_PSYMBOL string) with
- *     
- * Returns: $(D_KEYWORD true) if the arguments is not $(D_KEYWORD null) and it
- *          represents an equivalent $(D_PSYMBOL string) ignoring case; $(D_KEYWORD false) otherwise
- *          
- * Throws: AssertException if the length of any of the strings is 0
- *          
- * See_Also: opEquals(Object)
- */
-bool equalsIgnoreCase (string str, string anotherString)
-in
-{
-	assert(str.length > 0, "mambo.string.equalsIgnoreCase: The length of the first string was 0");
-	assert(anotherString.length > 0, "mambo.string.equalsIgnoreCase: The length of the second string was 0");
-}
-body
-{	
-	if (str == anotherString)
-		return true;
-
-	return toFold(str) == toFold(anotherString);
-}
-
-/**
- * Compares the $(D_PSYMBOL wstring) to another $(D_PSYMBOL wstring), ignoring case
- * considerations. Two wstrings are considered equal ignoring case if they are of the
- * same length and corresponding characters in the two wstrings are equal ignoring case.
- * 
- * Params:
- *     str = The $(D_PSYMBOL wstring) first string to compre to
- *     anotherString = The $(D_PSYMBOL wstring) to compare the first $(D_PSYMBOL wstring) against
- *     
- * Returns: $(D_KEYWORD true) if the argument is not $(D_KEYWORD null) and it
- *          represents an equivalent $(D_PSYMBOL wstring) ignoring case; (D_KEYWORD
- *          false) otherwise
- *          
- * Throws: AssertException if the length of any of the wstrings is 0
- *          
- * See_Also: opEquals(Object)
- */
-bool equalsIgnoreCase (wstring str, wstring anotherString)
-in
-{
-	assert(str.length > 0, "mambo.string.equalsIgnoreCase: The length of the first string was 0");
-	assert(anotherString.length > 0, "mambo.string.equalsIgnoreCase: The length of the second string was 0");
-}
-body
-{
-	if (str == anotherString)
-		return true;
-
-	version (Tango)
-		return toFold(str) == toFold(anotherString);
-
-	else
-		return toFold(toUTF8(str)) == toFold(toUTF8(anotherString));
-}
-
-/**
- * Compares the $(D_PSYMBOL dstring) to another $(D_PSYMBOL dstring), ignoring case
- * considerations. Two wstrings are considered equal ignoring case if they are of the
- * same length and corresponding characters in the two wstrings are equal ignoring case.
- * 
- * Params:
- *     str = The $(D_PSYMBOL dstring) first string to compare to
- *     anotherString = The $(D_PSYMBOL wstring) to compare the first $(D_PSYMBOL dstring) against
- *     
- * Returns: $(D_KEYWORD true) if the argument is not $(D_KEYWORD null) and it
- *          represents an equivalent $(D_PSYMBOL dstring) ignoring case; $(D_KEYWORD false) otherwise
- *          
- * Throws: AssertException if the length of any of the dstrings are 0
- *          
- * See_Also: opEquals(Object)
- */
-bool equalsIgnoreCase (dstring str, dstring anotherString)
-in
-{
-	assert(str.length > 0, "mambo.string.equalsIgnoreCase: The length of the first string was 0");
-	assert(anotherString.length > 0, "mambo.string.equalsIgnoreCase: The length of the second string was 0");
-}
-body
-{
-	if (str == anotherString)
-		return true;
-
-	version (Tango)
-		return toFold(str) == toFold(anotherString);
-
-	else
-		return toFold(toUTF8(str)) == toFold(toUTF8(anotherString));
-}
-
-/**
- * Returns the char value at the specified index. An index ranges from 0 to length - 1.
- * The first $(D_KEYWORD char) value of the sequence is at index 0, the next at index 1,
- * and so on, as for array indexing.
- * 
- * Params:
- * 	   str = the string to get the $(D_KEYWORD char) from
- *     index = the index of the $(D_KEYWORD char) value.
- *     
- * Returns: the $(D_KEYWORD char) value at the specified index of the string.
- *          The first $(D_KEYWORD char) value is at index 0.
- * 
- * Throws: AssertException if the length of the string is 0
- * Throws: AssertException if the $(D_CODE index) argument is
- *         not less than the length of the string.
- */
-char charAt (string str, size_t index)
-in
-{
-	assert(str.length > 0, "mambo.string.charAt: The length of the string was 0");
-	assert(index <= str.length, "mambo.string.charAt: The index was to greater than the length of the string");
-}
-body
-{
-	return str[index];
-}
-
-/**
- * Returns the $(D_KEYWORD char) value at the specified index. An index ranges from 0 to
- * length - 1. The first $(D_KEYWORD char) value of the sequence is at index 0, the next
- * at index 1, and so on, as for array indexing.
- * 
- * Params:
- * 	   str = the wstring to get the $(D_KEYWORD char) from
- *     index = the index of the $(D_KEYWORD char) value.
- *     
- * Returns: the $(D_KEYWORD char) value at the specified index of the wstring.
- *          The first $(D_KEYWORD char) value is at index 0.
- * 
- * Throws: AssertException if the length of the wstring is 0
- * Throws: AssertException if the $(D_CODE index) argument is
- *         not less than the length of the wstring.
- */
-wchar charAt (wstring str, size_t index)
-in
-{
-	assert(str.length > 0, "mambo.string.charAt: The length of the string was 0");
-	assert(index <= str.length, "mambo.string.charAt: The index was to greater than the length of the string");
-}
-body
-{
-	return str[index];
-}
-
-/**
- * Returns the $(D_KEYWORD char) value at the specified index. An index ranges from 0 to
- * length - 1. The first $(D_KEYWORD char) value of the sequence is at index 0, the next
- * at index 1, and so on, as for array indexing.
- * 
- * Params:
- * 	   str = the dstring to get the $(D_KEYWORD char) from
- *     index = the index of the $(D_KEYWORD char) value.
- *     
- * Returns: the $(D_KEYWORD char) value at the specified index of the dstring.
- *          The first $(D_KEYWORD char) value is at index 0.
- * 
- * Throws: AssertException if the length of the dstring is 0
- * Throws: AssertException if the $(D_CODE index) argument is
- *         not less than the length of the dstring.
- */
-dchar charAt (dstring str, size_t index)
-in
-{
-	assert(str.length > 0, "mambo.string.charAt: The length of the string was 0");
-	assert(index <= str.length, "mambo.string.charAt: The index was to greater than the length of the string");
-}
-body
-{
-	return str[index];
-}
-
-/**
- * Returns a new string that is a substring of the specified string. The substring begins
- * at the specified $(D_PARAM beginIndex) and extends to the character at index
- * $(D_PARAM endIndex) - 1. Thus the length of the substring is $(D_PARAM endIndex - beginIndex).
- * 
- * Examples:
- * ---
- * "hamburger".substring(4, 8) returns "urge"
- * "smiles".substring(1, 5) returns "mile"
- * ---
- * 
- * Params:
- * 	   str = the string to get the substring from
- *     beginIndex = the beginning index, inclusive.
- *     endIndex = the ending index, exclusive.
- *     
- * Returns: the specified substring.
- * 
- * Throws: AssertException if the length of the string is 0
- * Throws: AssertException if the $(D_PARAM beginIndex) is 
- * 		   larger than $(D_PARAM endIndex).
- * Throws: AssertException if $(D_PARAM endIndex) is larger than the 
- *  	   length of the $(D_PSYMBOL string).
- */
-string substring (string str, size_t beginIndex, size_t endIndex)
-in
-{
-	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
-	assert(beginIndex < endIndex, "mambo.string.substring: The first index was greater the second");
-	assert(endIndex <= str.length, "mambo.string.substring: The second index was greater then the length of the string");
-}
-body
-{
-	version (Tango) return str[beginIndex .. endIndex].dup;
-	else return str[beginIndex .. endIndex].idup;
-}
-
-/**
- * Returns a new string that is a substring of the specified string. The substring begins
- * at the specified $(D_PARAM beginIndex) and extends to the character at index
- * $(D_PARAM endIndex) - 1. Thus the length of the substring is $(D_PARAM endIndex - beginIndex).
- * 
- * Examples:
- * ---
- * "hamburger".substring(4, 8) returns "urge"
- * "smiles".substring(1, 5) returns "mile"
- * ---
- * 
- * Params:
- * 	   str = the string to get the substring from
- *     beginIndex = the beginning index, inclusive.
- *     endIndex = the ending index, exclusive.
- *     
- * Returns: the specified substring.
- * 
- * Throws: AssertException if the length of the string is 0
- * Throws: AssertException if the $(D_PARAM beginIndex) is 
- * 		   larger than $(D_PARAM endIndex).
- * Throws: AssertException if $(D_PARAM endIndex) is larger than the 
- *  	   length of the $(D_PSYMBOL string).
- */
-wstring substring (wstring str, size_t beginIndex, size_t endIndex)
-in
-{
-	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
-	assert(beginIndex < endIndex, "mambo.string.substring: The first index was greater the second");
-	assert(endIndex <= str.length, "mambo.string.substring: The second index was greater then the length of the string");
-}
-body
-{
-	version (Tango) return str[beginIndex .. endIndex].dup;
-	else return str[beginIndex .. endIndex].idup;
-}
-
-/**
- * Returns a new string that is a substring of the specified string. The substring begins
- * at the specified $(D_PARAM beginIndex) and extends to the character at index
- * $(D_PARAM endIndex) - 1. Thus the length of the substring is $(D_PARAM endIndex - beginIndex).
- * 
- * Examples:
- * ---
- * "hamburger".substring(4, 8) returns "urge"
- * "smiles".substring(1, 5) returns "mile"
- * ---
- * 
- * Params:
- * 	   str = the string to get the substring from
- *     beginIndex = the beginning index, inclusive.
- *     endIndex = the ending index, exclusive.
- *     
- * Returns: the specified substring.
- * 
- * Throws: AssertException if the length of the string is 0
- * Throws: AssertException if the $(D_PARAM beginIndex) is 
- * 		   larger than $(D_PARAM endIndex).
- * Throws: AssertException if $(D_PARAM endIndex) is larger than the 
- *  	   length of the $(D_PSYMBOL string).
- */
-dstring substring (dstring str, size_t beginIndex, size_t endIndex)
-in
-{
-	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
-	assert(beginIndex < endIndex, "mambo.string.substring: The first index was greater the second");
-	assert(endIndex <= str.length, "mambo.string.substring: The second index was greater then the length of the string");
-}
-body
-{
-	version (Tango) return str[beginIndex .. endIndex].dup;
-	else return str[beginIndex .. endIndex].idup;
-}
-
-/**
- * Returns a new string that is a substring of the specified string. The substring begins
- * with the character at the specified index and extends to the end of the string. 
- * 
- * Examples:
- * ---
- * "unhappy".substring(2) returns "happy"
- * "Harbison".substring(3) returns "bison"
- * "emptiness".substring(9) returns "" (an empty string)
- * ---
- * 
- * Params:
- *     str = the string to get the substring from
- *     beginIndex = the beginning index, inclusive
- *     
- * Returns: the specified substring
- * 
- * Throws: AssertException if the length of the string is 0
- * Throws: AssertException if the $(D_PARAM beginIndex) is 
- * 		   larger than the length of the string.
- */
-string substring (string str, size_t index)
-in
-{
-	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
-	assert(index < str.length, "mambo.string.substring: The index was greater than the length of the string");
-}
-body
-{
-	return str.substring(index, str.length);
-}
-
-/**
- * Returns a new string that is a substring of the specified string. The substring begins
- * with the character at the specified index and extends to the end of the string. 
- * 
- * Examples:
- * ---
- * "unhappy".substring(2) returns "happy"
- * "Harbison".substring(3) returns "bison"
- * "emptiness".substring(9) returns "" (an empty string)
- * ---
- * 
- * Params:
- *     str = the string to get the substring from
- *     beginIndex = the beginning index, inclusive
- *     
- * Returns: the specified substring
- * 
- * Throws: AssertException if the length of the string is 0
- * Throws: AssertException if the $(D_PARAM beginIndex) is 
- * 		   larger than the length of the string.
- */
-wstring substring (wstring str, size_t index)
-in
-{
-	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
-	assert(index < str.length, "mambo.string.substring: The index was greater than the length of the string");
-}
-body
-{
-	return str.substring(index, str.length);
-}
-
-/**
- * Returns a new string that is a substring of the specified string. The substring begins
- * with the character at the specified index and extends to the end of the string. 
- * 
- * Examples:
- * ---
- * "unhappy".substring(2) returns "happy"
- * "Harbison".substring(3) returns "bison"
- * "emptiness".substring(9) returns "" (an empty string)
- * ---
- * 
- * Params:
- *     str = the string to get the substring from
- *     beginIndex = the beginning index, inclusive
- *     
- * Returns: the specified substring
- * 
- * Throws: AssertException if the length of the string is 0
- * Throws: AssertException if the $(D_PARAM beginIndex) is 
- * 		   larger than the length of the string.
- */
-dstring substring (dstring str, size_t index)
-in
-{
-	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
-	assert(index < str.length, "mambo.string.substring: The index was greater than the length of the string");
-}
-body
-{
-	return str.substring(index, str.length);
-}
-
-/**
- * Returns a new string that is a substring of the given string.
- * 
- * This substring is the character sequence that starts at character
- * position pos and has a length of n characters.
- * 
- * Params:
- *     str = the string to get the substring from
- *     pos = position of a character in the current string to be used 
- *     		 as starting character for the substring.
- *     n = Length of the substring. If this value would make the 
- *     	   substring to span past the end of the current string content,
- *     	   only those characters until the end of the string are used. 
- *     	   size_t.max is the greatest possible value for an element of
- *     	   type size_t, therefore, when this value is used, all the
- *     	   characters between pos and the end of the string are used as
- *     	   the initialization substring.
- *     
- * Returns: a string containing a substring of the given string
- * 
- * Throws: AssertException if pos is greater than the length of the string
- */
-string substr (string str, size_t pos = 0, size_t n = size_t.max)
-in
-{
-	assert(pos < str.length, "mambo.string.substr: The given position was greater than the length of the string.");
-}
-body
-{
-	size_t end;
-	
-	if (n == size_t.max)
-		end = str.length;
-	
-	else
-	{
-		end = pos + n;
-		
-		if (end > str.length)
-			end = str.length;
-	}
-	
-	version (Tango) return str[pos .. end].dup;
-	else return str[pos .. end].idup;
-}
-
-/**
- * Returns a new string that is a substring of the given string.
- * 
- * This substring is the character sequence that starts at character
- * position pos and has a length of n characters.
- * 
- * Params:
- *     str = the string to get the substring from
- *     pos = position of a character in the current string to be used 
- *     		 as starting character for the substring.
- *     n = Length of the substring. If this value would make the 
- *     	   substring to span past the end of the current string content,
- *     	   only those characters until the end of the string are used. 
- *     	   size_t.max is the greatest possible value for an element of
- *     	   type size_t, therefore, when this value is used, all the
- *     	   characters between pos and the end of the string are used as
- *     	   the initialization substring.
- *     
- * Returns: a string containing a substring of the given string
- * 
- * Throws: AssertException if pos is greater than the length of the string
- */
-wstring substr (wstring str, size_t pos = 0, size_t n = size_t.max)
-in
-{
-	assert(pos < str.length, "mambo.string.substr: The given position was greater than the length of the string.");
-}
-body
-{
-	size_t end;
-	
-	if (n == size_t.max)
-		end = str.length;
-	
-	else
-	{
-		end = pos + n;
-		
-		if (end > str.length)
-			end = str.length;
-	}
-	
-	version (Tango) return str[pos .. end].dup;
-	else return str[pos .. end].idup;
-}
-
-/**
- * Returns a new string that is a substring of the given string.
- * 
- * This substring is the character sequence that starts at character
- * position pos and has a length of n characters.
- * 
- * Params:
- *     str = the string to get the substring from
- *     pos = position of a character in the current string to be used 
- *     		 as starting character for the substring.
- *     n = Length of the substring. If this value would make the 
- *     	   substring to span past the end of the current string content,
- *     	   only those characters until the end of the string are used. 
- *     	   size_t.max is the greatest possible value for an element of
- *     	   type size_t, therefore, when this value is used, all the
- *     	   characters between pos and the end of the string are used as
- *     	   the initialization substring.
- *     
- * Returns: a string containing a substring of the given string
- * 
- * Throws: AssertException if pos is greater than the length of the string
- */
-dstring substr (dstring str, size_t pos = 0, size_t n = size_t.max)
-in
-{
-	assert(pos < str.length, "mambo.string.substr: The given position was greater than the length of the string.");
-}
-body
-{
-	size_t end;
-	
-	if (n == size_t.max)
-		end = str.length;
-	
-	else
-	{
-		end = pos + n;
-		
-		if (end > str.length)
-			end = str.length;
-	}
-	
-	version (Tango) return str[pos .. end].dup;
-	else return str[pos .. end].idup;
-}
-
-/**
- * Finds the first occurence of sub in str
- * 
- * Params:
- *     str = the string to find in
- *     sub = the substring to find
- *     start = where to start finding
- *     
- * Returns: the index of the substring or size_t.max when nothing was found
- */
-size_t find (string str, string sub)
-{
-	version (Tango)
-	{
-		size_t index = str.locatePattern(sub);
-		
-		if (index == str.length)
-			return size_t.max;
-		
-		return index;
-	}
-	
-	else
-		return std.string.indexOf(str, sub);
-	
-}
-
-/**
- * Finds the first occurence of sub in str
- * 
- * Params:
- *     str = the string to find in
- *     sub = the substring to find
- *     start = where to start finding
- *     
- * Returns: the index of the substring or size_t.max when nothing was found
- */
-size_t find (wstring str, wstring sub)
-{
-	version (Tango)
-	{
-		size_t index = str.locatePattern(sub);
-		
-		if (index == str.length)
-			return size_t.max;
-		
-		return index;
-	}
-	
-	else
-		return std.string.indexOf(str, sub);
-}
-
-/**
- * Finds the first occurence of sub in str
- * 
- * Params:
- *     str = the string to find in
- *     sub = the substring to find
- *     start = where to start finding
- *     
- * Returns: the index of the substring or size_t.max when nothing was found
- */
-size_t find (dstring str, dstring sub)
-{
-	version (Tango)
-	{
-		size_t index = str.locatePattern(sub);
-		
-		if (index == str.length)
-			return size_t.max;
-		
-		return index;
-	}
-	
-	else
-		return std.string.indexOf(str, sub);
-}
-
-/**
- * Compares to strings, ignoring case differences. Returns 0 if the content
- * matches, less than zero if a is "less" than b, or greater than zero
- * where a is "bigger".
- * 
- * Params:
- *     a = the first array 
- *     b = the second array
- *     end = the index where the comparision will end
- *     
- * Returns: Returns 0 if the content matches, less than zero if a is 
- * 			"less" than b, or greater than zero where a is "bigger".
- * 
- * See_Also: mambo.collection.array.compare
- */
-int compareIgnoreCase (U = size_t) (string a, string b, U end = U.max)
-{
-	return a.toFold().compare(b.toFold(), end);
-}
-
-/**
- * Compares to strings, ignoring case differences. Returns 0 if the content
- * matches, less than zero if a is "less" than b, or greater than zero
- * where a is "bigger".
- * 
- * Params:
- *     a = the first array 
- *     b = the second array
- *     end = the index where the comparision will end
- *     
- * Returns: Returns 0 if the content matches, less than zero if a is 
- * 			"less" than b, or greater than zero where a is "bigger".
- * 
- * See_Also: mambo.collection.array.compare
- */
-int compareIgnoreCase (U = size_t) (wstring a, wstring b, U end = U.max)
-{
-	return a.toFold().compare(b.toFold(), end);
-}
-
-/**
- * Compares to strings, ignoring case differences. Returns 0 if the content
- * matches, less than zero if a is "less" than b, or greater than zero
- * where a is "bigger".
- * 
- * Params:
- *     a = the first array 
- *     b = the second array
- *     end = the index where the comparision will end
- *     
- * Returns: Returns 0 if the content matches, less than zero if a is 
- * 			"less" than b, or greater than zero where a is "bigger".
- * 
- * See_Also: mambo.collection.array.compare
- */
-int compareIgnoreCase (U = size_t) (dstring a, dstring b, U end = U.max)
-{
-	return a.toFold().compare(b.toFold(), end);
-}
-
-/**
- * Compares to strings, ignoring case differences. Returns 0 if the content
- * matches, less than zero if a is "less" than b, or greater than zero
- * where a is "bigger".
- * 
- * Params:
- *     a = the first array 
- *     b = the second array
- *     end = the index where the comparision will end
- *     
- * Returns: Returns 0 if the content matches, less than zero if a is 
- * 			"less" than b, or greater than zero where a is "bigger".
- * 
- * See_Also: mambo.string.compareIgnoreCase
- */
-alias compareIgnoreCase icompare;
-
-/**
- * Checks if the given character is a hexdecimal digit character.
- * Hexadecimal digits are any of: 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
- * 
- * Params:
- *     ch = the character to be checked
- *     
- * Returns: true if the given character is a hexdecimal digit character otherwise false
- */
-bool isHexDigit (dchar ch)
-{
-	version (Tango)
-	{
-		switch (ch)
-		{
-			case 'A': return true;				
-			case 'B': return true;
-			case 'C': return true;
-			case 'D': return true;
-			case 'E': return true;
-			case 'F': return true;
-			
-			case 'a': return true;
-			case 'b': return true;
-			case 'c': return true;
-			case 'd': return true;
-			case 'e': return true;
-			case 'f': return true;
-			
-			default: break;
-		}
-		
-		if (isDigit(ch))
-			return true;
-	}
-
-	else
-		if (isxdigit(ch) != 0)
-			return true;
-		
-	return false;
-}
-
-/*version (Tango)
-{
-	string toString (string str)
-	{
-		return str;
-	}
-	
-	string toString (wstring str)
-	{
-		return tango.text.convert.Utf.toString(str);
-	}
-	
-	string toString (dstring str)
-	{
-		return tango.text.convert.Utf.toString(str);
-	}
-}*/
-
-version (Phobos)
-{	
-	/**
-	 * Converts the given string to C-style 0 terminated string.
-	 * 
-	 * Params:
-	 *     str = the string to convert
-	 *     
-	 * Returns: the a C-style 0 terminated string.
-	 */
-	dchar* toString32z (dstring str)
-	{
-		return (str ~ '\0').dup.ptr;
-	}
-	
-	/**
-	 * Converts a C-style 0 terminated string to a wstring
-	 * 
-	 * Params:
-	 *     str = the C-style 0 terminated string
-	 *     
-	 * Returns: the converted wstring
-	 */
-	wstring fromString16z (wchar* str)
-	{
-		return str[0 .. strlen(str)].idup;
-	}
-	
-	/**
-	 * Converts a C-style 0 terminated string to a dstring
-	 * Params:
-	 *     str = the C-style 0 terminated string
-	 *     
-	 * Returns: the converted dstring
-	 */
-	dstring fromString32z (dchar* str)
-	{
-		return str[0 .. strlen(str)].idup;
-	}
-	
-	/**
-	 * Gets the length of the given C-style 0 terminated string
-	 * 
-	 * Params:
-	 *     str = the C-style 0 terminated string to get the length of
-	 *     
-	 * Returns: the length of the string
-	 */
-	size_t strlen (wchar* str)
-	{
-		size_t i = 0;
-		
-		if (str)
-			while(*str++)
-				++i;
-		
-		return i;
-	}
-	
-	/**
-	 * Gets the length of the given C-style 0 terminated string
-	 * 
-	 * Params:
-	 *     str = the C-style 0 terminated string to get the length of
-	 *     
-	 * Returns: the length of the string
-	 */
-	size_t strlen (dchar* str)
-	{
-		size_t i = 0;
-		
-		if (str)
-			while(*str++)
-				++i;
-		
-		return i;
-	}
-}
\ No newline at end of file
--- a/orange/xml/PhobosXML.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/xml/PhobosXML.d	Wed Aug 03 21:58:21 2011 +0200
@@ -131,7 +131,7 @@
 import std.string;
 import std.encoding;
 
-immutable cdata = "<![CDATA[";
+enum cdata = "<![CDATA[";
 
 final class Attribute : Element
 {
@@ -1015,7 +1015,7 @@
 				string[] b = item.pretty(indent);
 				foreach(s;b)
 				{
-					a ~= rjustify(s,s.length + indent);
+					a ~= rightJustify(s,s.length + indent);
 				}
 			}
 			a ~= tag.toEndString;
@@ -1250,7 +1250,7 @@
 
 			string toEndString() { return "</" ~ name ~ ">"; }
 
-			string toEmptyString() { return toNonEndString() ~ " />"; }
+			string toEmptyString() { return toNonEndString() ~ "/>"; }
 		}
 
 		/**
--- a/orange/xml/XMLDocument.d	Mon Oct 04 20:45:32 2010 +0200
+++ b/orange/xml/XMLDocument.d	Wed Aug 03 21:58:21 2011 +0200
@@ -12,7 +12,7 @@
 	import tango.text.xml.Document;
 	import tango.io.Stdout;
 	
-	import orange.util.string;
+	import orange.core.string;
 }
 
 else
@@ -25,7 +25,7 @@
 	version = Phobos;
 }
 
-import orange.util.io;
+import orange.core.io;
 	
 template Char (T)
 {
@@ -228,7 +228,7 @@
 		void attach (Node node)
 		{
 			version (Tango) this.node.move(node.node);
-			else this.node.elements ~= node.node;
+			else this.node ~= node.node;
 		}
 	}
 	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/Serializer.d	Wed Aug 03 21:58:21 2011 +0200
@@ -0,0 +1,616 @@
+
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Nov 5, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module tests.Serializer;
+
+private:
+
+import orange.serialization.Serializer;
+import orange.serialization.archives.XMLArchive;
+import orange.core.io;
+import orange.core.string;
+
+bool containsDefaultXmlContent (string source)
+{
+	return source.containsXmlHeader() &&
+		   source.containsArchive() &&
+		   source.containsXmlTag("data");
+}
+
+bool containsXmlHeader (string source)
+{
+	return source.contains(`<?xml version="1.0" encoding="UTF-8"?>`);
+}
+
+bool containsArchive (string source)
+{
+	return source.containsArchiveHeader() && source.contains("</archive>");
+}
+
+bool containsArchiveHeader (string source)
+{
+	return source.contains(`<archive type="org.dsource.orange.xml" version="1.0.0">`) ||
+		source.contains(`<archive version="1.0.0" type="org.dsource.orange.xml">`);
+}
+
+bool containsXmlTag (string source, string tag, bool simple = false)
+{
+	return source.containsXmlTag(tag, null, null, simple);
+}
+
+bool containsXmlTag (string source, string tag, string attributes, bool simple = false)
+{
+	return source.containsXmlTag(tag, attributes, null, simple);
+}
+
+bool containsXmlTag (string source, string tag, string attributes, string content, bool simple = false)
+{
+	string pattern = '<' ~ tag;
+		
+	if (attributes.length > 0)
+		pattern ~= ' ' ~ attributes;
+	
+	if (simple)
+		return source.contains(pattern ~ "/>");
+
+	if (content.length > 0)
+		return source.contains(pattern ~ '>' ~ content ~ "</" ~ tag ~ '>');
+
+	return source.contains(pattern ~ '>') && source.contains("</" ~ tag ~ '>');
+}
+
+enum Foo { a, b, c }
+typedef int Int;
+
+class A
+{
+	equals_t opEquals (Object other)
+	{
+		if (auto o = cast(A) other)
+			return true;
+		
+		return false;
+	}
+}
+
+struct B
+{
+	version (Tango)
+	{
+		equals_t opEquals (B b)
+		{
+			return true;
+		}
+	}
+	
+	else
+	{
+		mixin(`bool opEquals (ref const B) const
+		{
+			return true;
+		}`);
+	}
+}
+
+class C { string str; wstring wstr; dstring dstr; }
+class D { int[] arr; }
+class E { int[int] aa; }
+class F { int value; int* ptr; int* ptr2; }
+class G { Foo foo; }
+
+int pointee;
+
+class H
+{
+	bool bool_;
+	byte byte_;
+	//cdouble cdouble_; // currently not suppported by to!()
+	//cent cent_; // currently not implemented but a reserved keyword
+	//cfloat cfloat_; // currently not suppported by to!()
+	char char_;
+	//creal creal_; // currently not suppported by to!()
+	dchar dchar_;
+	double double_;
+	float float_;
+	//idouble idouble_; // currently not suppported by to!()
+	//ifloat ifloat_; // currently not suppported by to!()
+	int int_;
+	//ireal ireal_;  // currently not suppported by to!()
+	long long_;
+	real real_;
+	short short_;
+	ubyte ubyte_;
+	//ucent ucent_; // currently not implemented but a reserved keyword
+	uint uint_;
+	ulong ulong_;
+	ushort ushort_;
+	
+	version (Tango)
+		wchar wchar_; // Phobos to!() function can't handle string -> wchar
+	
+	equals_t opEquals (Object other)
+	{
+		if (auto o =  cast(H) other)
+		{
+			auto result = bool_ == o.bool_ &&
+				   byte_ == o.byte_ &&
+				   //cdouble_ == o.cdouble_ && // currently not suppported by to!()
+				   //cent_ == o.cent_ && // currently not implemented but a reserved keyword
+				   //cfloat_ == o.cfloat_ && // currently not suppported by to!()
+				   char_ == o.char_ &&
+				   //creal_ == o.creal_ && // currently not suppported by to!()
+				   dchar_ == o.dchar_ &&
+				   double_ == o.double_ &&
+				   float_ == o.float_ &&
+				   //idouble_ == o.idouble_ && // currently not suppported by to!()
+				   //ifloat_ == o.ifloat_ && // currently not suppported by to!()
+				   int_ == o.int_ &&
+				   //ireal_ == o.ireal_ &&  // currently not suppported by to!()
+				   long_ == o.long_ &&
+				   real_ == o.real_ &&
+				   short_ == o.short_ &&
+				   ubyte_ == o.ubyte_ &&
+				   //ucent_ == o.ucent_ && // currently not implemented but a reserved keyword
+				   uint_ == o.uint_ &&
+				   ulong_ == o.ulong_ &&
+				   ushort_ == o.ushort_;
+				
+				   version (Tango)
+				   		return result && wchar_ == o.wchar_;
+
+				   else
+						return result;
+		}
+		
+		return false;
+	}
+}
+
+class I
+{
+	Int a;
+}
+
+class J
+{
+	int[] firstSource;
+	int[] firstSlice;
+	
+	int[] secondSlice;
+	int[] secondSource;
+}
+
+class K
+{
+	int[int] a;
+	int[int] b;
+}
+
+import orange.test.UnitTester;
+Serializer serializer;
+XMLArchive!(char) archive;
+
+A a;
+B b;
+C c;
+D d;
+E e;
+F f;
+F fDeserialized;
+G g;
+H h;
+I i;
+J j;
+J jDeserialized;
+K k;
+
+string data;
+
+unittest
+{
+	archive = new XMLArchive!(char);
+	serializer = new Serializer(archive);
+	
+	a = new A;
+	
+	c = new C;
+	c.str = "foo";
+	c.wstr = "bar";
+	c.dstr = "foobar";
+	
+	
+	d = new D;
+	d.arr = [27, 382, 283, 3820, 32, 832].dup;
+	
+	e = new E;
+	e.aa = [3 : 4, 1 : 2, 39 : 472, 6 : 7];
+	
+	pointee = 3;
+	f = new F;
+	f.value = 9;
+	f.ptr = &f.value;
+	f.ptr2 = &pointee;
+	
+	g = new G;
+	g.foo = Foo.b;
+	
+	h = new H;	
+	h.bool_ = true;
+	h.byte_ = 1;
+	h.char_ = 'a';
+	//h.cdouble_ = 0.0 + 0.0 * 1.0i; // currently not supported by to!() 
+	//h.cfloat_ = 0.0f + 0.0f * 1.0i; // currently not supported by to!() 
+	//h.creal_ = 0.0 + 0.0 * 1.0i; // currently not supported by to!() 
+	h.dchar_ = 'b';
+	h.double_ = 0.0;
+	h.float_ = 0.0f;
+	//h.idouble_ = 0.0 * 1.0i; // currently not supported by to!() 
+	//h.ifloat_ = 0.0f * 1.0i; // currently not supported by to!()
+	h.int_ = 1;
+	//h.ireal_ = 0.0 * 1.0i; // currently not supported by to!()
+	h.long_ = 1L;
+	h.real_ = 0.0;
+	h.short_ = 1;
+	h.ubyte_ = 1U;
+	h.uint_ = 1U;
+	h.ulong_ = 1LU;
+	h.ushort_ = 1U;
+	
+	version (Tango)
+		h.wchar_ = 'c';
+	
+	i = new I;
+	i.a = 1;
+	
+	j = new J;
+	j.firstSource = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].dup;
+	j.firstSlice = j.firstSource[3 .. 7];
+	j.secondSource = [10, 11, 12, 13, 14, 15].dup;
+	j.secondSlice = j.secondSource[1 .. 4];
+	
+	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 {
+				serializer.reset;
+				serializer.serialize(a);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().contains(`<object runtimeType="tests.Serializer.A" type="A" key="0" id="0"/>`));
+			};
+		};
+		
+		describe("deserialize object") in {
+			it("should return a deserialized object equal to the original object") in {
+				auto aDeserialized = serializer.deserialize!(A)(archive.data);
+				assert(a == aDeserialized);
+			};
+		};
+		
+		describe("serialize struct") in {
+			it("should return a serialized struct") in {
+				serializer.reset;
+				serializer.serialize(B());
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().contains(`<struct type="B" key="0" id="0"/>`));
+			};
+		};
+		
+		describe("deserialize struct") in {
+			it("should return a deserialized struct equal to the original struct") in {
+				auto bDeserialized = serializer.deserialize!(B)(archive.data);
+				assert(b == bDeserialized);
+			};
+		};
+		
+		describe("serialize strings") in {
+			it("should return serialized strings") in {
+				serializer.reset;
+				serializer.serialize(c);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.C" type="C" key="0" id="0"`));
+				
+				version (Tango) string type = "char";
+				else string type = "immutable(char)";
+
+				assert(archive.data().containsXmlTag("string", `type="` ~ type ~ `" length="3" key="str" id="1"`, "foo"));
+				
+				version (Tango) type = "wchar";
+				else type = "immutable(wchar)";
+
+				assert(archive.data().containsXmlTag("string", `type="` ~ type ~ `" length="3" key="wstr" id="2"`, "bar"));
+				
+				version (Tango) type = "dchar";
+				else type = "immutable(dchar)";
+				
+				assert(archive.data().containsXmlTag("string", `type="` ~ type ~ `" length="6" key="dstr" id="3"`, "foobar"));
+			};
+		};
+		
+		describe("deserialize string") in {
+			it("should return a deserialized string equal to the original string") in {
+				auto cDeserialized = serializer.deserialize!(C)(archive.data);
+				assert(c.str == cDeserialized.str);
+			};
+		};
+		
+		describe("serialize array") in {
+			it("should return a serialized array") in {
+				serializer.reset;
+				serializer.serialize(d);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.D" type="D" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("array", `type="int" length="6" key="arr" id="1"`));
+				assert(archive.data().containsXmlTag("int", `key="0" id="2"`, "27"));
+				assert(archive.data().containsXmlTag("int", `key="1" id="3"`, "382"));
+				assert(archive.data().containsXmlTag("int", `key="2" id="4"`, "283"));
+				assert(archive.data().containsXmlTag("int", `key="3" id="5"`, "3820"));
+				assert(archive.data().containsXmlTag("int", `key="4" id="6"`, "32"));
+				assert(archive.data().containsXmlTag("int", `key="5" id="7"`, "832"));
+			};
+		};
+		
+		describe("deserialize array") in {
+			it("should return a deserialize array equal to the original array") in {
+				auto dDeserialized = serializer.deserialize!(D)(archive.data);
+				assert(d.arr == dDeserialized.arr);
+			};
+		};
+		
+		describe("serialize associative array") in {
+			it("should return a serialized associative array") in {
+				serializer.reset();
+				serializer.serialize(e);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.E" type="E" key="0" id="0"`));
+				version (Tango) 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" id="2"`, "1"));
+				assert(archive.data().containsXmlTag("value", `key="0"`));
+				assert(archive.data().containsXmlTag("int", `key="0" id="3"`, "2"));
+				
+				assert(archive.data().containsXmlTag("key", `key="1"`));
+				assert(archive.data().containsXmlTag("int", `key="1" id="4"`, "3"));
+				assert(archive.data().containsXmlTag("value", `key="1"`));
+				assert(archive.data().containsXmlTag("int", `key="1" id="5"`, "4"));
+				
+				assert(archive.data().containsXmlTag("key", `key="2"`));
+				assert(archive.data().containsXmlTag("int", `key="2" id="6"`, "6"));
+				assert(archive.data().containsXmlTag("value", `key="2"`));
+				assert(archive.data().containsXmlTag("int", `key="2" id="7"`, "7"));
+				
+				assert(archive.data().containsXmlTag("key", `key="3"`));
+				assert(archive.data().containsXmlTag("int", `key="3" id="8"`, "39"));
+				assert(archive.data().containsXmlTag("value", `key="3"`));
+				assert(archive.data().containsXmlTag("int", `key="3" id="9"`, "472"));
+			};
+		};
+		
+		describe("deserialize associative array") in {
+			it("should return an associative array equal to the original associative array") in {
+				auto eDeserialized = serializer.deserialize!(E)(archive.data);
+				
+				foreach (k, v ; eDeserialized.aa)
+					assert(e.aa[k] == v);
+				
+				//assert(e.aa == eDeserialized.aa); // cannot compare associative array
+			};
+		};
+		
+		describe("serialize pointer") in {
+			it("should return a serialized pointer") in {
+				serializer.reset();
+				serializer.serialize(f);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.F" type="F" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("pointer", `key="ptr" id="2"`));
+				assert(archive.data().containsXmlTag("reference", `key="1"`, "1"));
+				assert(archive.data().containsXmlTag("int", `key="value" id="1"`, "9"));
+			};
+		};
+		
+		describe("deserialize pointer") in {
+			fDeserialized = serializer.deserialize!(F)(archive.data);
+
+			it("should return a deserialized pointer equal to the original pointer") in {
+				assert(*f.ptr == *fDeserialized.ptr);
+			};
+			
+			it("the pointer should point to the deserialized value") in {
+				assert(fDeserialized.ptr == &fDeserialized.value);
+			};
+		};
+		
+		describe("serialize enum") in {
+			it("should return a serialized enum") in {
+				serializer.reset();
+				serializer.serialize(g);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.G" type="G" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("enum", `type="Foo" baseType="int" key="foo" id="1"`, "1"));
+			};
+		};
+
+		
+		describe("deserialize enum") in {
+			it("should return an enum equal to the original enum") in {
+				auto gDeserialized = serializer.deserialize!(G)(archive.data);
+				assert(g.foo == gDeserialized.foo);
+			};
+		};
+		
+		describe("serialize primitives") in {
+			it("should return serialized primitives") in {
+				serializer.reset;
+				serializer.serialize(h);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.H" type="H" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("bool", `key="bool_" id="1"`, "true"));
+				assert(archive.data().containsXmlTag("byte", `key="byte_" id="2"`, "1"));
+				assert(archive.data().containsXmlTag("char", `key="char_" id="3"`, "a"));
+				assert(archive.data().containsXmlTag("dchar", `key="dchar_" id="4"`, "b"));
+				assert(archive.data().containsXmlTag("double", `key="double_" id="5"`, "0"));
+				assert(archive.data().containsXmlTag("float", `key="float_" id="6"`, "0"));
+				assert(archive.data().containsXmlTag("int", `key="int_" id="7"`, "1"));
+				assert(archive.data().containsXmlTag("long", `key="long_" id="8"`, "1"));
+				assert(archive.data().containsXmlTag("real", `key="real_" id="9"`, "0"));
+				assert(archive.data().containsXmlTag("short", `key="short_" id="10"`, "1"));
+				assert(archive.data().containsXmlTag("ubyte", `key="ubyte_" id="11"`, "1"));
+				assert(archive.data().containsXmlTag("uint", `key="uint_" id="12"`, "1"));
+				assert(archive.data().containsXmlTag("ulong", `key="ulong_" id="13"`, "1"));
+				assert(archive.data().containsXmlTag("ushort", `key="ushort_" id="14"`, "1"));
+				
+				version (Tango)
+					assert(archive.data().containsXmlTag("wchar", `key="wchar_" id="15"`, "c"));
+			};
+		};
+		
+		describe("deserialize primitives") in {
+			it("should return deserialized primitives equal to the original primitives") in {
+				auto hDeserialized = serializer.deserialize!(H)(archive.data);
+				assert(h == hDeserialized);
+			};
+		};
+		
+		describe("serialize typedef") in {
+			it("should return a serialized typedef") in {
+				serializer.reset();
+				serializer.serialize(i);
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.I" type="I" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("typedef", `type="Int" key="a" id="2"`));
+				assert(archive.data().containsXmlTag("int", `key="1" id="3"`, "1"));
+			};
+		};
+		
+		// describe("deserialize typedef") in {
+		// 	it("should return a deserialized typedef equal to the original typedef") in {
+		// 		auto iDeserialized = serializer.deserialize!(I)(archive.data);
+		// 		assert(i.a == iDeserialized.a);
+		// 	};
+		// };
+		
+		describe("serialize slices") in {
+			it("should return serialized slices") in {
+				serializer.reset();
+				serializer.serialize(j);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.J" type="J" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("array", `type="int" length="10" key="firstSource" id="1"`));
+				
+				assert(archive.data().containsXmlTag("int", `key="0" id="2"`, "0"));
+				assert(archive.data().containsXmlTag("int", `key="1" id="3"`, "1"));
+				assert(archive.data().containsXmlTag("int", `key="2" id="4"`, "2"));
+				assert(archive.data().containsXmlTag("int", `key="3" id="5"`, "3"));
+				assert(archive.data().containsXmlTag("int", `key="4" id="6"`, "4"));
+				assert(archive.data().containsXmlTag("int", `key="5" id="7"`, "5"));
+				assert(archive.data().containsXmlTag("int", `key="6" id="8"`, "6"));
+				assert(archive.data().containsXmlTag("int", `key="7" id="9"`, "7"));
+				assert(archive.data().containsXmlTag("int", `key="8" id="10"`, "8"));
+				assert(archive.data().containsXmlTag("int", `key="9" id="11"`, "9"));
+
+				version (Tango)
+				{
+					assert(archive.data().containsXmlTag("slice", `key="firstSlice" offset="3" length="4"`, "1"));
+					assert(archive.data().containsXmlTag("slice", `key="secondSlice" offset="1" length="3"`, "21"));
+				}
+
+				assert(archive.data().containsXmlTag("array", `type="int" length="6" key="secondSource" id="21"`));
+				
+				assert(archive.data().containsXmlTag("int", `key="0" id="22"`, "10"));
+				assert(archive.data().containsXmlTag("int", `key="1" id="23"`, "11"));
+				assert(archive.data().containsXmlTag("int", `key="2" id="24"`, "12"));
+				assert(archive.data().containsXmlTag("int", `key="3" id="25"`, "13"));
+				assert(archive.data().containsXmlTag("int", `key="4" id="26"`, "14"));
+				assert(archive.data().containsXmlTag("int", `key="5" id="27"`, "15"));
+			};
+		};
+		
+		describe("deserialize slices") in {
+			jDeserialized = serializer.deserialize!(J)(archive.data);
+			
+			it("should return deserialized strings equal to the original strings") in {
+				assert(j.firstSource == jDeserialized.firstSource);
+				assert(j.secondSource == jDeserialized.secondSource);
+			};
+			
+			it("should return deserialized slices equal to the original slices") in {
+				assert(j.firstSlice == jDeserialized.firstSlice);
+				assert(j.secondSlice == jDeserialized.secondSlice);
+			};
+			
+			it("the slices should be equal to a slice of the original sources") in {
+				assert(jDeserialized.firstSource[3 .. 7] == jDeserialized.firstSlice);
+				assert(jDeserialized.secondSource[1 .. 4] == jDeserialized.secondSlice);
+				
+				assert(j.firstSource[3 .. 7] == jDeserialized.firstSlice);
+				assert(j.secondSource[1 .. 4] == jDeserialized.secondSlice);
+			};
+			
+			it("the slices should be able to modify the sources") in {
+				jDeserialized.firstSlice[0] = 55;
+				jDeserialized.secondSlice[0] = 3;
+
+				assert(jDeserialized.firstSource == [0, 1, 2, 55, 4, 5, 6, 7, 8, 9]);
+				assert(jDeserialized.secondSource == [10, 3, 12, 13, 14, 15]);
+			};
+		};
+		
+		describe("serialize associative array references") in {
+			it("should return a serialized associative array and a serialized reference") in {
+				serializer.reset();
+				serializer.serialize(k);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.K" type="K" key="0" id="0"`));
+				version (Tango) 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" id="2"`, "1"));
+				assert(archive.data().containsXmlTag("value", `key="0"`));
+				assert(archive.data().containsXmlTag("int", `key="0" id="3"`, "2"));
+				
+				assert(archive.data().containsXmlTag("key", `key="1"`));
+				assert(archive.data().containsXmlTag("int", `key="1" id="4"`, "3"));
+				assert(archive.data().containsXmlTag("value", `key="1"`));
+				assert(archive.data().containsXmlTag("int", `key="1" id="5"`, "4"));
+				
+				assert(archive.data().containsXmlTag("key", `key="2"`));
+				assert(archive.data().containsXmlTag("int", `key="2" id="6"`, "6"));
+				assert(archive.data().containsXmlTag("value", `key="2"`));
+				assert(archive.data().containsXmlTag("int", `key="2" id="7"`, "7"));
+				
+				assert(archive.data().containsXmlTag("key", `key="3"`));
+				assert(archive.data().containsXmlTag("int", `key="3" id="8"`, "39"));
+				assert(archive.data().containsXmlTag("value", `key="3"`));
+				assert(archive.data().containsXmlTag("int", `key="3" id="9"`, "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);
+			};
+		};
+	};
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/all.d	Wed Aug 03 21:58:21 2011 +0200
@@ -0,0 +1,15 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Nov 5, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module tests.all;
+
+import orange.test.UnitTester;
+import tests.Serializer;
+
+void main ()
+{
+	run;
+}
\ No newline at end of file