/** Just a simple hack to have interfaces implemented by structs ... because I can :P Tested on DMD 1.039 [win32], GDC (various versions) [linux32] and codepad.org

Output:

Entering main
Foo.func1 called ; val1 = 3.141590, val2 = Hello, world!
Foo.func2 called ; val1 = 3.141590, val2 = Hello, world!
Foo.func2 called ; val1 = 3.141590, val2 = Hello, world!
Foo.func3 called ; val1 = 3.141590, val2 = Hello, world! ; p1 = 123, p2 = some parameter
Leaving main
*/


module structIface;

extern (C) int printf(char*, ...);



// ---- evil implementation
char[] structImplementInterface(char[] iface, char[][] funcs) {
        char[] res = "private {";
        res ~= \n"alias typeof(*this) _iface_"~iface~"_ThisType;";

        foreach (func; funcs) {
                res ~= \n"static assert (is(typeof(&"~iface~".init."~func~")),
                        `The interface "~iface~" doesn't declare a '"~func~"' 
function, `
`thus struct `~_iface_"~iface~"_ThisType.stringof~` cannot implement it`);";
                res ~= \n"static void _iface_" ~ iface ~ "_func_" ~ func ~ "() 
{";
                version (GNU) {
res ~= \n\t"asm { naked; sub dword ptr 4[ESP], _iface_" ~ iface ~ "_vtbl.offsetof; jmp " ~ func ~ "; }";
                } else {
res ~= \n\t"asm { naked; sub EAX, _iface_" ~ iface ~ "_vtbl.offsetof; jmp " ~ func ~ "; }";
                }
                res ~= \n"}";
        }
        res ~= \n ~ iface ~ " as" ~ iface ~ "() {";
        res ~= \n\t"return cast("~iface~")cast(void*)&_iface_" ~ iface ~ 
"_vtbl;";
        res ~= \n"}";

        res ~= \n"void** _iface_" ~ iface ~ "_vtbl = cast(void**)([";
        res ~= \n\t"null";            // for classinfo
        foreach (func; funcs) {
                res ~= ",\n\tcast(void*)&Foo._iface_" ~ iface ~ "_func_" ~ func;
        }
        res ~= \n"]).ptr;";
        res ~= "}";

        return res;
}
// ---- end of the evil implementation


interface IFoo {
        void func1();
        void func2();
}

interface IBar {
        void func2();
        void func3(int, char[]);
}


struct Foo {
        float val1;
        char[] val2;

        void func1() {
                printf("Foo.func1 called ; val1 = %f, val2 = %.*s"\n, val1, 
val2);
        }

        void func2() {
                printf("Foo.func2 called ; val1 = %f, val2 = %.*s"\n, val1, 
val2);
        }

        void func3(int p1, char[] p2) {
printf("Foo.func3 called ; val1 = %f, val2 = %.*s ; p1 = %d, p2 = %.*s"\n, val1, val2, p1, p2);
        }

        mixin(structImplementInterface("IFoo", ["func1", "func2"]));
        mixin(structImplementInterface("IBar", ["func2", "func3"]));
}


void main() {
        printf("Entering main"\n);

        Foo f;
        f.val1 = 3.14159f;
        f.val2 = "Hello, world!";

        IFoo fi = f.asIFoo;
        fi.func1();
        fi.func2();

        IBar bi = f.asIBar;
        bi.func2();
        bi.func3(123, "some parameter");

        printf("Leaving main"\n);
}


/**
The concept is pretty simple. The mixin creates a vtable which points to a set of generated functions of the form { adjust the 'this' ptr; jump to the real function; }. Finally, the "InterfaceName asInterfaceName()" functions generated inside the struct return pointers to the corresponding vtables.

Now this would be so much nicer if there was a way to iterate the functions of an interface at compile time in D1... Can we have D1 plus __traits? Pleaaaase? Pretty please with a cherry on top?

Thanks to downs, Hxal and Jarrett!
*/


--
Tomasz Stachowiak
http://h3.team0xf.com/
h3/h3r3tic on #D freenode

Reply via email to