Created
September 2, 2016 13:16
-
-
Save rjmcguire/d469e4f785da7734a16a9b7ccc17a83c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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