Skip to content

Instantly share code, notes, and snippets.

@rjmcguire
Created September 2, 2016 13:16
Show Gist options
  • Save rjmcguire/d469e4f785da7734a16a9b7ccc17a83c to your computer and use it in GitHub Desktop.
Save rjmcguire/d469e4f785da7734a16a9b7ccc17a83c to your computer and use it in GitHub Desktop.
// from: http://dpaste.dzfl.pl/50a8a7aa1267
// d references this dpaste:
/*
from: Basile.B via Digitalmars-d <[email protected]>
reply-to: "digitalmars.D" <[email protected]>
to: [email protected]
date: Sat, Nov 28, 2015 at 12:31 AM
subject: Struct multiple inheritance - another solution
mailing list: [email protected] Filter messages from this mailing list
mailed-by: puremagic.com
*/
module runnable;
import std.stdio;
import std.typecons, std.traits, std.meta;
// utils to generate the delegate and interface functions
auto getFuncPtr(T, string member, int overloadIndex)()
if (is(T == class) || is(T==struct))
{
return &__traits(getOverloads, T, member)[overloadIndex];
}
template FuncFunction(T, string member, int overloadIndex)
if (is(T == class) || is(T==struct))
{
alias FuncFunction = typeof(&__traits(getOverloads, T, member)[overloadIndex]);
}
template FuncDelegate(T, string member, int overloadIndex)
if (is(T == class) || is(T==struct))
{
alias ReturnT = ReturnType!(__traits(getOverloads, T, member)[overloadIndex]);
alias ParamsT = Parameters!(__traits(getOverloads, T, member)[overloadIndex]);
enum alias_declaration = "alias FuncDelegate = " ~ ReturnT.stringof
~ " delegate" ~ ParamsT.stringof ~ ";";
mixin(alias_declaration);
}
template DelegateCallParams(T, string member, int overloadIndex)
{
template foldStringTuple(T...)
{
static if (T.length == 0)
enum foldStringTuple = "";
else static if (T.length > 1)
enum foldStringTuple = T[0] ~ "," ~ foldStringTuple!(T[1 .. $]);
else
enum foldStringTuple = T[0];
}
enum items = (ParameterIdentifierTuple!(__traits(getOverloads, T, member)[overloadIndex]));
enum DelegateCallParams = "(" ~ foldStringTuple!items ~ ")";
}
auto delegateName(string member)()
{
return member ~ "_DG";
}
template InterfaceFunc(T, string member, int overloadIndex)
if (is(T == class) || is(T==struct))
{
import std.string: indexOf;
enum temp = FuncFunction!(T, member, overloadIndex).stringof;
enum pos = indexOf(temp, "function");
enum InterfaceFunc = temp[0 .. pos] ~ member ~ temp[pos + 8 .. $];
}
// generate the declaration
auto StructInterface(I,S)()
if (is(I == interface) && is(S==struct))
{
enum theCtor(S) =
"this(){}
this()(void* instance){patch(instance);}
void patch(void* instance)
{
foreach(member;__traits(allMembers, typeof(this)))
{
static if (member == \"__ctor\")
continue;
else static if (member == \"Monitor\")
continue;
else static if (member == \"factory\")
continue;
else
{
auto thisDelegate = &__traits(getMember, typeof(this), member);
thisDelegate.ptr = instance;
foreach(smember;__traits(allMembers, " ~ S.stringof ~ "))
foreach(i, overload;__traits(getOverloads, " ~ S.stringof ~ ", smember))
{
static if (smember ~ \"_DG\" == member) // + need to compare parameters & return type
thisDelegate.funcptr = getFuncPtr!(" ~ S.stringof ~ ", smember, i);
}
}
}
}
";
auto classString = "class " ~ S.stringof ~ I.stringof ~ " : " ~ I.stringof;
classString ~= "\n{ \n " ~ theCtor!S;
foreach(imember; __traits(allMembers, I))
foreach(ioverload; __traits(getOverloads, I, imember))
static if (imember != "patch")
{
foreach(smember; __traits(allMembers, S))
static if (isCallable!(__traits(getMember, S, smember)))
foreach(soverload; __traits(getOverloads, S, smember))
static if (is(typeof(soverload) == typeof(ioverload)) && smember == imember)
{
auto delegate_declaration = FuncDelegate!(S, smember, 0).stringof ~ delegateName!smember ~ ";";
auto delegate_call = delegateName!smember ~ DelegateCallParams!(S, smember, 0);
auto interface_entry = InterfaceFunc!(S, smember, 0) ~ "{ return " ~ delegate_call ~ ";}";
classString ~= " " ~ delegate_declaration ~ "\n";
classString ~= " " ~ interface_entry ~ "\n";
}
}
return classString ~ "}";
}
// test types
interface Foo
{
uint bar(string a, int b);
void baz(char c);
void testInstance(uint value);
/*
The problem is that this additional method (useless for a class)
is needed to create a struct interface
*/
void patch(void* instance);
}
struct Fog
{
uint testValue;
uint bar(string a, int b) {return 0;}
void baz(char c){writeln("works");}
void testInstance(uint value){testValue = value;}
}
// mix the declaration
mixin(StructInterface!(Foo,Fog));
void main(string[] args)
{
Fog fog;
if (auto runtime_interface = getInterface!Foo("Fog", &fog))
{
runtime_interface.baz('v');
runtime_interface.testInstance(8);
assert(fog.testValue == 8);
}
else writeln("no luck today...");
}
// instead of cast(stuff) I
I getInterface(I)(string structname, void* instance)
if (is(I == interface))
{
auto result = Object.factory("runnable." ~ structname ~ I.stringof);
if (I itf = cast(I) result)
{
itf.patch(instance);
return itf;
}
else return null;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment