fork download
  1. import std.stdio;
  2. import std.traits;
  3. import std.stream;
  4. import std.metastrings;
  5.  
  6. private template SerializerParameterType(T)
  7. {
  8. enum SerializerParameterType = "ref " ~ T.stringof;
  9. }
  10.  
  11. private template SerializerParameterType(T : Object)
  12. {
  13. enum SerializerParameterType = T.stringof;
  14. }
  15.  
  16. template AddStreamSerialization(T)
  17. {
  18. enum
  19. {
  20. AddStreamSerialization = "public void Serialize(" ~ SerializerParameterType!(T) ~ " t, OutputStream stream) { " ~
  21. GenerateFieldSerialization!(T,0,__traits(allMembers,T)).result ~
  22. "}" ~
  23. "public void Deserialize(" ~ SerializerParameterType!(T) ~ " t, InputStream stream) { " ~
  24. GenerateFieldDeserialization!(T,0,__traits(allMembers,T)).result ~
  25. "}"
  26. };
  27. }
  28.  
  29. private template GenerateFieldSerialization(T,int typeIndex, Ts...)
  30. {
  31. static if(typeIndex >= T.tupleof.length)
  32. {
  33. enum result = "";
  34. }
  35. else static if (Ts.length == 1)
  36. {
  37. static if(isBoolean!(FieldTypeTuple!(T)[typeIndex]))
  38. {
  39. enum result = "stream.write(t." ~ Ts[0] ~" ? \"true\" : \"false\");\n";
  40. }
  41. else static if(isNumeric!(FieldTypeTuple!(T)[typeIndex]))
  42. {
  43. enum result = "stream.write(t." ~ Ts[0] ~ ");\n";
  44. }
  45. else static if(isSomeString!(FieldTypeTuple!(T)[typeIndex]))
  46. {
  47. enum result = "stream.write(t." ~ Ts[0] ~ ");\n";
  48. }
  49. else
  50. {
  51. // It's a complex type(struct or class), call member.Serialize()
  52. enum result = "Serialize(t." ~ Ts[0] ~ ",stream);";
  53. }
  54. }
  55. else static if(is(typeof(mixin(T.stringof ~ "." ~ Ts[0])) == function))
  56. {
  57. // It's a function, skip it
  58. enum result = GenerateFieldSerialization!(T,typeIndex,Ts[1..$]).result;
  59. }
  60. else
  61. {
  62. enum result = GenerateFieldSerialization!(T, typeIndex, Ts[0]).result ~ GenerateFieldSerialization!(T,typeIndex+1, Ts[1..$]).result;
  63. }
  64. }
  65.  
  66. private template GenerateFieldDeserialization(T,int typeIndex, Ts...)
  67. {
  68. static if(typeIndex >= T.tupleof.length)
  69. {
  70. enum result = "";
  71. }
  72. else static if (Ts.length == 1)
  73. {
  74. static if(isBoolean!(FieldTypeTuple!(T)[typeIndex]))
  75. {
  76. enum boolName = "readBool_" ~ Ts[0];
  77. enum result = "char[] " ~ boolName ~ "; stream.read(" ~ boolName ~ "); t." ~ Ts[0] ~ "= (" ~ boolName ~ " == \"true\") ? true : false;\n";
  78. }
  79. else static if(isNumeric!(FieldTypeTuple!(T)[typeIndex]))
  80. {
  81. enum result = "stream.read(t." ~ Ts[0] ~ ");\n";
  82. }
  83. else static if(isSomeString!(FieldTypeTuple!(T)[typeIndex]))
  84. {
  85. enum stringName = "readString_" ~ Ts[0];
  86. enum result = "char[] " ~ stringName ~ "; stream.read(" ~ stringName ~ "); t." ~ Ts[0] ~ " = cast(string)" ~ stringName ~ ";\n";
  87. }
  88. else
  89. {
  90. // It's a complex type(struct or class), call member.Deserialize()
  91. enum result = "Deserialize(t." ~ Ts[0] ~ ",stream);";
  92. }
  93. }
  94. else static if(is(typeof(mixin(T.stringof ~ "." ~ Ts[0])) == function))
  95. {
  96. // It's a function, skip it
  97. enum result = GenerateFieldDeserialization!(T,typeIndex,Ts[1..$]).result;
  98. }
  99. else
  100. {
  101. enum result = GenerateFieldDeserialization!(T, typeIndex, Ts[0]).result ~ GenerateFieldDeserialization!(T,typeIndex+1, Ts[1..$]).result;
  102. }
  103. }
  104.  
  105. struct Data
  106. {
  107. int dataId;
  108. bool isValidData;
  109. int numberOfEnemies;
  110. string test;
  111. int Version;
  112. }
  113.  
  114. mixin(AddStreamSerialization!(Data));
  115.  
  116. class MyObject
  117. {
  118. public int m_id;
  119. public Data m_data;
  120.  
  121. public void AMethod()
  122. {
  123. }
  124.  
  125. public bool AutoDelete;
  126.  
  127. public void AnotherMethod()
  128. {
  129. //write();
  130. }
  131.  
  132. public int RefCount;
  133.  
  134. public void Method1()
  135. {
  136. }
  137.  
  138. //public int[3] StaticArray;
  139. //public int[] DynArray;
  140. }
  141.  
  142. mixin(AddStreamSerialization!(MyObject));
  143.  
  144. template GetField(T, int typeIndex, Ts...)
  145. {
  146. static if(typeIndex >= T.tupleof.length)
  147. {
  148. pragma(msg, Format!("case 1: typeIndex=%s,Ts.length=%s",typeIndex,Ts.length));
  149. enum result = "";
  150. }
  151. else static if (Ts.length == 1)
  152. {
  153. pragma(msg, Format!("case 2: typeIndex=%s,Ts.length=%s",typeIndex,Ts.length));
  154. enum result = Ts[0] ~ ": " ~ FieldTypeTuple!(T)[typeIndex].stringof ~ "\n";
  155. }
  156. else static if(is(typeof(mixin(T.stringof ~ "." ~ Ts[0])) == function))
  157. {
  158. pragma(msg, Format!("case 3: typeIndex=%s,Ts.length=%s",typeIndex,Ts.length));
  159. // It's a function, skip it
  160. enum result = GetField!(T,typeIndex,Ts[1..$]).result;
  161. }
  162. else
  163. {
  164. pragma(msg, Format!("case 4: typeIndex=%s,Ts.length=%s",typeIndex,Ts.length));
  165. enum result = GetField!(T, typeIndex, Ts[0]).result ~ GetField!(T,typeIndex+1, Ts[1..$]).result;
  166. }
  167. }
  168.  
  169. template GetFieldList(T)
  170. {
  171. enum { result = GetField!(T, 0, __traits(allMembers, T)).result };
  172. }
  173.  
  174. void SerializeData()
  175. {
  176. auto dumpFile = new std.stream.File("dumpData.txt", FileMode.Out);
  177.  
  178. Data myData;
  179. myData.dataId = 1;
  180. myData.isValidData = true;
  181. myData.numberOfEnemies = 123456;
  182. myData.Version = 2;
  183. myData.test = "This is so awesome !";
  184.  
  185. myData.Serialize(dumpFile);
  186. dumpFile.close();
  187.  
  188. auto dumpFile2 = new std.stream.File("dumpData.txt", FileMode.In);
  189. Data readData;
  190. readData.Deserialize(dumpFile2);
  191.  
  192. writeln("Read Data:");
  193. writefln("dataId=%s", readData.dataId);
  194. writefln("isValidData=%s", readData.isValidData);
  195. writefln("numberOfEnemies=%s", readData.numberOfEnemies);
  196. writefln("Version=%s", readData.Version);
  197. writefln("test=%s", readData.test);
  198.  
  199. dumpFile2.close();
  200. }
  201.  
  202. void SerializeMyObject()
  203. {
  204. auto dumpFile = new std.stream.File("dumpMyObject.txt", FileMode.Out);
  205.  
  206. auto myObject = new MyObject;
  207. myObject.m_id = 0xdead;
  208. myObject.m_data.dataId = 2;
  209. myObject.m_data.isValidData = false;
  210. myObject.m_data.numberOfEnemies = 654321;
  211. myObject.m_data.Version = 3;
  212. myObject.m_data.test = "D just got 20% cooler !";
  213. myObject.AutoDelete = false;
  214. myObject.RefCount = 1;
  215.  
  216. myObject.Serialize(dumpFile);
  217. dumpFile.close();
  218.  
  219. auto dumpFile2 = new std.stream.File("dumpMyObject.txt", FileMode.In);
  220. auto readMyObject = new MyObject;
  221. readMyObject.Deserialize(dumpFile2);
  222.  
  223. writeln("Read MyObject:");
  224. writefln("m_id=%s", readMyObject.m_id);
  225. writefln("AutoDelete=%s",readMyObject.AutoDelete);
  226. writefln("RefCount=%s", readMyObject.RefCount);
  227. writefln("m_data.dataId=%s", readMyObject.m_data.dataId);
  228. writefln("m_data.isValidData=%s", readMyObject.m_data.isValidData);
  229. writefln("m_data.numberOfEnemies=%s", readMyObject.m_data.numberOfEnemies);
  230. writefln("m_data.Version=%s", readMyObject.m_data.Version);
  231. writefln("m_data.test=%s", readMyObject.m_data.test);
  232.  
  233. dumpFile2.close();
  234. }
  235.  
  236. void main()
  237. {
  238. SerializeData();
  239. SerializeMyObject();
  240.  
  241. pragma(msg, "Data template expansion")
  242. writeln("\nFields of Data: ");
  243. write(GetFieldList!(Data).result);
  244.  
  245. writeln(" ");
  246.  
  247. pragma(msg, "MyObject template expansion")
  248. writeln("Fields of MyObject: ");
  249. write(GetFieldList!(MyObject).result);
  250. readln();
  251. }
Compilation error #stdin compilation error #stdout 0.01s 2120KB
stdin
Standard input is empty
compilation info
prog.d(37): Error: template instance template 'isBoolean' is not defined
prog.d(37): Error: expression isBoolean!(int) is not constant or does not evaluate to a bool
stdout

Standard output is empty