/** An old serializer utility.
Copyright: Denis Shelomovskij 2010
License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: Denis Shelomovskij
*/
module serializer;
version(Win32) static assert(real.sizeof == 10);
else version(linux) static assert(real.sizeof == 12);
else static assert(0, "A new OS? Good!");
version(LittleEndian) { }
else version(BigEndian) static assert(0, "BigEndian? Good!");
else static assert(0, "LittleEndian or BigEndian?!");
import std.file, std.stream, std.traits;
///Data serialization helper
void serialize(T)(Stream s, in T t) {
SerializationStream!false(s).eat!T(t);
}
///ditto
void deserialize(T)(Stream s, out T t) {
SerializationStream!true(s).eat!T(t);
}
///Data serialization helper
void[] serialize(T)(in T t) {
scope s = new MemoryStream();
s.readable = false;
serialize(s, t);
return s.data();
}
///ditto
void deserialize(T)(in void[] data, out T t) {
scope s = new MemoryStream(cast(ubyte[])data);
s.writeable = false;
deserialize(s, t);
}
///File serialization helper
void serialize(T)(in string file, in T t) {
write(file, serialize(t));
}
///ditto
void deserialize(T)(in string file, out T t) {
deserialize(read(file), t);
}
private:
struct SerializationStream(bool read) {
const bool write = !read;
Stream stream;
//int l=0;
void eat(T)(ref T t) {//char[] text;for(int i=0; i<l; ++i) text ~= '\t';
static assert(!is(T == union), "can't eat union");
static if(is(T == struct)) {
//msg(text~"+ struct "~T.stringof);++l;
static if(is(typeof(t.ownStreamProcess)))
t.streamProcess(this);
else
foreach(i, el; t.tupleof)
eat!(typeof(el))(t.tupleof[i]);
//--l;msg(text~"- struct "~T.stringof, t);
} else static if(is(T == class)) {
//msg(text~"+ class "~T.stringof);++l;
bool isNull = t is null;
eat!bool(isNull);
if(isNull) {
static if(read)
t = null;
} else {
static if(read)
t = new T();
static if(is(typeof(t.ownStreamProcess)))
t.streamProcess(this);
else
foreach(i, el; t.tupleof)
eat!(typeof(el))(t.tupleof[i]);
}
//msg(text~"- class "~T.stringof, t);
} else {
//D1: static assert(isAtomicType!(T) | is(T == enum), T.stringof);
static assert(__traits(isArithmetic, T), T.stringof);
auto varr = cast(ubyte[])(&t)[0 .. 1];
static if(real.sizeof > 10 && is(T == real)) {
const i = real.sizeof - 10;
static if(write)
assert(varr[10 .. real.sizeof] == (new ubyte[i]));
else
varr[10 .. real.sizeof] = 0;
varr.length = 10;
}
static if(write)
stream.write(varr);
else
stream.read(varr);
}
}
//Запоминаем, когда это массив длины 0, а когда null
void eat(T: T[])(ref T[] tarr) {
//msg(write ? "write" : "read", "[]", T.stringof);
int len;
static if(write) {
len = tarr is null ? -1 : tarr.length;
eat!int(len);
foreach(el; tarr)
eat!(typeof(el))(el);
} else {
eat!int(len);
if(len == -1)
tarr = null;
else if(len == 0)
tarr = (cast(T*)"".ptr)[0..0];
else {
tarr.length = len;
foreach(ref el; tarr)
eat!(typeof(el))(el);
}
}
//msg('\t', T.stringof, tarr);
}
void eat(T: T[U], size_t U)(T[U] tarr) {
static if(write)
foreach(el; tarr)
eat!(typeof(el))(el);
else
foreach(ref el; tarr)
eat!(typeof(el))(el);
}
}