On Wed, Aug 12, 2009 at 4:52 PM, Rory McGuire<rjmcgu...@gmail.com> wrote: > Here is some code I wrote which enables wrapping a proxy around an object. > I am using it for my serialization library. It works in D1(1.046) and D2 > (2.031) > > Posting it here for reference by all before I add to much of the stuff > specific to my use, should make it easier to follow. > > usage: new ProxyClass!(A, cast(string)"getInt setInt getString"); would > implement the methods getInt setInt and getString from A in the new class. > > the code below will fail to compile but not before printing the generated > code to stdout. > > Shin Fujishiro has made some new templates for D2 which will make it so I > can get rid of the "setInt getInt getString" part which would make the > usage for D2: new ProxyClass!A; > which would be great! > > -Rory > > ============================================ > // author: Rory McGuire, rjmcgu...@gmail.com > import std.stdio; > import std.typetuple; > import std.traits; > import std.metastrings; > > //import serializer; > > // this CTF from somewhere on news.digitalmars.com > string[] splitFuncs(string str) { > string[] res; > while (str.length > 0) { > while (str.length > 0 && (' ' == str[0] || ',' == str[0])) { > str = str[1..$]; > } > int to = 0; > for (; to < str.length && str[to] != ' ' && str[to] != ','; ++to) > {} > if (to > 0) { > res ~= str[0..to]; > str = str[to..$]; > } > } > return res; > } > > string MethodTypeTuple_mixin(alias a)(string[] methods) { > string ret = "TypeTuple!("~ "typeof(&C.init."~methods[0]~")"; > foreach (method; methods[1..$]) { > ret ~= ",typeof(&C.init."~method~")"; > } > ret ~= ")"; > return ret; > } > > > > // test case > > class A { > int a; > this(int a) { > this.a = a; > } > int getInt(string intname) { > return a; > } > > void setInt(int i) { > a = i; > } > string getString(string s) { > return s ~"1234"; > } > } > > > string ProxyMethods_mixin(alias C, string methodstr)() { > string ret; > foreach(i, t; mixin(MethodTypeTuple_mixin!(C)(splitFuncs > (methodstr)))) { > // output function header > ret ~= "\t"~ReturnType!(t).stringof ~" "~ splitFuncs > (methodstr)[i]~"("; > // output first arg > ret ~= ParameterTypeTuple!(t)[0].stringof~" arg"; > // output remainder of args > foreach (j, t1; ParameterTypeTuple!(t)[1..$]) { > ret ~= ","~t1.stringof~" > arg"~std.metastrings.ToString!(j); > } > // output body > ret ~= ") {\n"; > // output serialization code > // send method name > ret ~= "\t\twritefln(\"serialize docall id\"); // the > method call byte id\n"; > ret ~= "\t\tbuffer ~= serialize!(string)(\""~splitFuncs > (methodstr)[i]~"\", s_state); /+ the method name +/\n"; > // send args > ret ~= "\t\tbuffer ~= serialize!("~ ParameterTypeTuple!(t) > [0].stringof~")(arg, s_state); /+ the first argument +/\n"; > foreach (j, t1; ParameterTypeTuple!(t)[1..$]) { > ret ~= "\t\tbuffer ~= serialize!("~ t1.stringof > ~")(arg"~ToString!(j)~", s_state); /+ argument "~ToString!(j)~" +/\n"; > } > // receive return type > static if (!is(ReturnType!(t) == void)) { > ret ~= "\t\treturn deserialize!("~ ReturnType! > (t).stringof ~")(buffer, des_state);\n"; > } > ret ~= "\t}\n"; > } > return ret; > } > > > class ProxyClass(alias C, string methodstr) { > ubyte[] buffer; > mixin(ProxyMethods_mixin!(C,methodstr)()); > pragma(msg, "class ProxyClass!("~C.stringof~", \""~ > methodstr ~"\") {\n\tubyte[] buffer;\n SerializerState s_state;\n > DeserializerState des_state;\n this() {s_state = new SerializerState(); > des_state = new DeserializerState(); }\n\n"~ ProxyMethods_mixin! > (C,methodstr)() ~"\n}\n"); > > } > > void main() { > auto pc = new ProxyClass!(A, cast(string)"getInt setInt > getString"); > writefln("ProxyClass: "~ pc.getString("asdf")); > } >
That code is screaming for some macros. Or variable interpolation at least. --bb