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