Semi Automated Object wrapping

Rory McGuire rjmcguire at gmail.com
Wed Aug 12 16:52:45 PDT 2009


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"));
}


More information about the Digitalmars-d-learn mailing list