import std.stdio;
import std.traits;
import std.stream;
import std.metastrings;
private template SerializerParameterType(T)
{
enum SerializerParameterType = "ref " ~ T.stringof;
}
private template SerializerParameterType(T : Object)
{
enum SerializerParameterType = T.stringof;
}
template AddStreamSerialization(T)
{
enum
{
AddStreamSerialization = "public void Serialize(" ~ SerializerParameterType!(T) ~ " t, OutputStream stream) { " ~
GenerateFieldSerialization!(T,0,__traits(allMembers,T)).result ~
"}" ~
"public void Deserialize(" ~ SerializerParameterType!(T) ~ " t, InputStream stream) { " ~
GenerateFieldDeserialization!(T,0,__traits(allMembers,T)).result ~
"}"
};
}
private template GenerateFieldSerialization(T,int typeIndex, Ts...)
{
static if(typeIndex >= T.tupleof.length)
{
enum result = "";
}
else static if (Ts.length == 1)
{
static if(isBoolean!(FieldTypeTuple!(T)[typeIndex]))
{
enum result = "stream.write(t." ~ Ts[0] ~" ? \"true\" : \"false\");\n";
}
else static if(isNumeric!(FieldTypeTuple!(T)[typeIndex]))
{
enum result = "stream.write(t." ~ Ts[0] ~ ");\n";
}
else static if(isSomeString!(FieldTypeTuple!(T)[typeIndex]))
{
enum result = "stream.write(t." ~ Ts[0] ~ ");\n";
}
else
{
// It's a complex type(struct or class), call member.Serialize()
enum result = "Serialize(t." ~ Ts[0] ~ ",stream);";
}
}
else static if(is(typeof(mixin(T.stringof ~ "." ~ Ts[0])) == function))
{
// It's a function, skip it
enum result = GenerateFieldSerialization!(T,typeIndex,Ts[1..$]).result;
}
else
{
enum result = GenerateFieldSerialization!(T, typeIndex, Ts[0]).result ~ GenerateFieldSerialization!(T,typeIndex+1, Ts[1..$]).result;
}
}
private template GenerateFieldDeserialization(T,int typeIndex, Ts...)
{
static if(typeIndex >= T.tupleof.length)
{
enum result = "";
}
else static if (Ts.length == 1)
{
static if(isBoolean!(FieldTypeTuple!(T)[typeIndex]))
{
enum boolName = "readBool_" ~ Ts[0];
enum result = "char[] " ~ boolName ~ "; stream.read(" ~ boolName ~ "); t." ~ Ts[0] ~ "= (" ~ boolName ~ " == \"true\") ? true : false;\n";
}
else static if(isNumeric!(FieldTypeTuple!(T)[typeIndex]))
{
enum result = "stream.read(t." ~ Ts[0] ~ ");\n";
}
else static if(isSomeString!(FieldTypeTuple!(T)[typeIndex]))
{
enum stringName = "readString_" ~ Ts[0];
enum result = "char[] " ~ stringName ~ "; stream.read(" ~ stringName ~ "); t." ~ Ts[0] ~ " = cast(string)" ~ stringName ~ ";\n";
}
else
{
// It's a complex type(struct or class), call member.Deserialize()
enum result = "Deserialize(t." ~ Ts[0] ~ ",stream);";
}
}
else static if(is(typeof(mixin(T.stringof ~ "." ~ Ts[0])) == function))
{
// It's a function, skip it
enum result = GenerateFieldDeserialization!(T,typeIndex,Ts[1..$]).result;
}
else
{
enum result = GenerateFieldDeserialization!(T, typeIndex, Ts[0]).result ~ GenerateFieldDeserialization!(T,typeIndex+1, Ts[1..$]).result;
}
}
struct Data
{
int dataId;
bool isValidData;
int numberOfEnemies;
string test;
int Version;
}
mixin(AddStreamSerialization!(Data));
class MyObject
{
public int m_id;
public Data m_data;
public void AMethod()
{
}
public bool AutoDelete;
public void AnotherMethod()
{
//write();
}
public int RefCount;
public void Method1()
{
}
//public int[3] StaticArray;
//public int[] DynArray;
}
mixin(AddStreamSerialization!(MyObject));
template GetField(T, int typeIndex, Ts...)
{
static if(typeIndex >= T.tupleof.length)
{
pragma(msg, Format!("case 1: typeIndex=%s,Ts.length=%s",typeIndex,Ts.length));
enum result = "";
}
else static if (Ts.length == 1)
{
pragma(msg, Format!("case 2: typeIndex=%s,Ts.length=%s",typeIndex,Ts.length));
enum result = Ts[0] ~ ": " ~ FieldTypeTuple!(T)[typeIndex].stringof ~ "\n";
}
else static if(is(typeof(mixin(T.stringof ~ "." ~ Ts[0])) == function))
{
pragma(msg, Format!("case 3: typeIndex=%s,Ts.length=%s",typeIndex,Ts.length));
// It's a function, skip it
enum result = GetField!(T,typeIndex,Ts[1..$]).result;
}
else
{
pragma(msg, Format!("case 4: typeIndex=%s,Ts.length=%s",typeIndex,Ts.length));
enum result = GetField!(T, typeIndex, Ts[0]).result ~ GetField!(T,typeIndex+1, Ts[1..$]).result;
}
}
template GetFieldList(T)
{
enum { result = GetField!(T, 0, __traits(allMembers, T)).result };
}
void SerializeData()
{
auto dumpFile = new std.stream.File("dumpData.txt", FileMode.Out);
Data myData;
myData.dataId = 1;
myData.isValidData = true;
myData.numberOfEnemies = 123456;
myData.Version = 2;
myData.test = "This is so awesome !";
myData.Serialize(dumpFile);
dumpFile.close();
auto dumpFile2 = new std.stream.File("dumpData.txt", FileMode.In);
Data readData;
readData.Deserialize(dumpFile2);
writeln("Read Data:");
writefln("dataId=%s", readData.dataId);
writefln("isValidData=%s", readData.isValidData);
writefln("numberOfEnemies=%s", readData.numberOfEnemies);
writefln("Version=%s", readData.Version);
writefln("test=%s", readData.test);
dumpFile2.close();
}
void SerializeMyObject()
{
auto dumpFile = new std.stream.File("dumpMyObject.txt", FileMode.Out);
auto myObject = new MyObject;
myObject.m_id = 0xdead;
myObject.m_data.dataId = 2;
myObject.m_data.isValidData = false;
myObject.m_data.numberOfEnemies = 654321;
myObject.m_data.Version = 3;
myObject.m_data.test = "D just got 20% cooler !";
myObject.AutoDelete = false;
myObject.RefCount = 1;
myObject.Serialize(dumpFile);
dumpFile.close();
auto dumpFile2 = new std.stream.File("dumpMyObject.txt", FileMode.In);
auto readMyObject = new MyObject;
readMyObject.Deserialize(dumpFile2);
writeln("Read MyObject:");
writefln("m_id=%s", readMyObject.m_id);
writefln("AutoDelete=%s",readMyObject.AutoDelete);
writefln("RefCount=%s", readMyObject.RefCount);
writefln("m_data.dataId=%s", readMyObject.m_data.dataId);
writefln("m_data.isValidData=%s", readMyObject.m_data.isValidData);
writefln("m_data.numberOfEnemies=%s", readMyObject.m_data.numberOfEnemies);
writefln("m_data.Version=%s", readMyObject.m_data.Version);
writefln("m_data.test=%s", readMyObject.m_data.test);
dumpFile2.close();
}
void main()
{
SerializeData();
SerializeMyObject();
pragma(msg, "Data template expansion")
writeln("\nFields of Data: ");
write(GetFieldList!(Data).result);
writeln(" ");
pragma(msg, "MyObject template expansion")
writeln("Fields of MyObject: ");
write(GetFieldList!(MyObject).result);
readln();
}