謎's キッチン

謎のひとりごと。Amazon欲しい物リストはこちら: https://www.amazon.co.jp/hz/wishlist/ls/CCPOV7C6JTD2

シリアライズ/デシリアライズ

醜いハックの塊。
その一: 戻り値に静的配列が使えない。
その二: Struct.tupleofをforeachした要素がコピーになってる。
その三: テンプレート+オーバーロードの問題(これは仕方ない気もするが)。

/**
 * Author: Nazo
 * License: Public Domain
 */
module nazo.serialize;
/**
 * シリアライズします。
 * Bugs: ポインタ/連想配列/float/double/realなどに未対応
 * Bugs: Tからrvの長さが一意に決まるのでそれを使うべし。
 */
ubyte[] serialize(T)(T t){
  ubyte[] rv;
  static if(is(T==struct)){
    foreach(x;t.tupleof)
      rv~=serialize(x);
  }else static if(__traits(isIntegral,T)){
    rv=(cast(ubyte*)[t].ptr)[0..T.sizeof];
  }else static if(__traits(isStaticArray,T)){
    rv=cast(ubyte[])t;
  }else static if(is(T U:U[])){
    rv=serialize(t.length) ~ cast(ubyte[])t;
  }else{
    assert(0,"unsupported");
  }
  return rv;
}

template ReturnType(T){
  static if(__traits(isStaticArray,T) && is(T U:U[])){
    alias U[] ReturnType;
  }else{
    alias T ReturnType;
  }
}

/**
 * デシリアライズします。
 * Bugs: ポインタ/連想配列/float/double/realなどに未対応
 */
ReturnType!(T) deserialize(T)(ubyte[] t){
  ubyte* ptr = t.ptr;
  return _deserialize!(T)(ptr);
}

private ReturnType!(T) _deserialize(T)(ref ubyte* t){
  ReturnType!(T) rv;
  static if(is(T==struct)){
    foreach(i,x;rv.tupleof){
      static if(__traits(isStaticArray,typeof(x)))
        rv.tupleof[i][]/*x[]=*/=_deserialize!(typeof(x))(t)[];
      else
        rv.tupleof[i]/*x=*/=_deserialize!(typeof(x))(t);
    }
  }else static if(__traits(isIntegral,T)){
    rv=*cast(T*)t;
    t+=T.sizeof;
  }else static if(__traits(isStaticArray,T)&&is(T U:U[])){
    rv=cast(U[])t[0..T.sizeof];
    t+=T.sizeof;
  }else static if(is(T U:U[])){
    int len = _deserialize!(size_t)(t);
    rv= (cast(U*)t)[0..len];
    t+=len*U.sizeof;
  }else{
    assert(0,"unsupported");
  }
  return rv;
}

import std.stdio;

struct Test{
  ubyte a;
  uint b;
  ubyte[2] c;
  ubyte[] d;
  string[] e;
}

void main(){
  ubyte[] data;
  Test test=Test(2,10,2,[3,4],["1","2"]);
  writefln(test.tupleof);
  data=serialize(test);
  writefln(data);
  test=deserialize!(Test)(data);
  writefln(test.tupleof);
}