Semi Automated Object wrapping

Rory McGuire rjmcguire at gmail.com
Thu Aug 13 00:43:31 PDT 2009


On Wed, 12 Aug 2009 17:03:17 -0700, Bill Baxter wrote:

> 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

Where would you propose that one would use 'macro'?


More information about the Digitalmars-d-learn mailing list