Semi Automated Object wrapping
Bill Baxter
wbaxter at gmail.com
Wed Aug 12 17:03:17 PDT 2009
On Wed, Aug 12, 2009 at 4:52 PM, Rory McGuire<rjmcguire at 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, rjmcguire at 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
More information about the Digitalmars-d-learn
mailing list