RPC and Dynamic function call
grauzone
none at example.net
Fri Nov 20 19:54:11 PST 2009
Denis Koroskin wrote:
> type-safe manner anymore (well, one could create a set of trampolines
> for each of set of types involved in a call, but I don't think it's
> reasonable or even possible; I'll look into it, too, though). That's why
Yes, it is possible. You'll have to pass the method as alias template
parameter. Then you get a tuple of the parameter types. You can foreach
over that tuple and serialize/deserialize the actual values and
read/write them from the tuple. You also can declare a nested function
that does the actual call to the server's function. That delegate can
have a type independent from the method, and thus can be stored in the
non-template world.
Basically like this (pseudo code):
//client function to invoke a specific RPC
//the parameters can be passed normally thanks to tuples
void makeDynamicCall(Params...)(Stream stream, char[] method, Params p) {
stream.write(method);
//serialize the parameters
foreach (int index, _; p) {
auto val = p[index];
stream.write!(typeof(val))(val);
}
}
alias void delegate(Stream) Stub;
//registry of server functions
Stub[char[]] stubs;
//the server network code calls this on incomming RPC requests
void receiveDynamicCall(Stream stream) {
auto method = stream.read!(char[])();
stubs[method].call(stream);
}
//the server calls this on program initialization
//he passes an alias to the server function, and its name
void registerStub(alias Function)(char[] name) {
//generate code to deserialize a RPC and to call the server
void stub(Stream stream) {
//you can get the param tuple of a function
//Phobos2 and Tango should have something similar
alias ParamTupleOfFunction!(Function) Params;
//deserialize the arguments
Params p;
foreach (int index, _; p) {
alias typeof(p[index]) PT;
p[index] = stream.read!(PT)();
}
//actually call the function
Function(p);
}
stubs[name] = &stub;
}
It all can be typesafe and non-compiler specific.
The question is; how much template bloat will this emit into the
application binary? You have to consider the instantiations of
Stream.read and Stream.write, too.
> Note that all the asm it uses is just 3 constructs: naked, ret and call!
> Everything else is implemented with a help of compiler (i.e. pushing
> arguments, grabbing result, stack alignment etc). My code is most
> probably not very portable (I didn't test it on anything other that
> Windows), it doesn't account x64 specifics etc, but it shouldn't be hard
> to fix.
Wow, I'm surprised that this works. Actually, I'd *like* to do it this
way, but the code is completely compiler and platform specific. Maybe it
also depends from the compiler code generator's mood if it works. And if
you want to deal with user-define types (structs), you're completely out
of luck.
More information about the Digitalmars-d
mailing list