1 ///
2 module aslike;
3 
4 import std.traits;
5 import std..string : join;
6 
7 ///
8 struct Like(T) if (is(T == interface))
9 {
10     private template dlgName(alias fn) { enum dlgName = "__dlg_" ~ fn.mangleof; }
11     private template fnAttr(alias fn)
12     {
13         enum fnAttr = [__traits(getFunctionAttributes, fn)].join(" ");
14     }
15 
16     static foreach (m; [__traits(allMembers, T)])
17     {
18         static if (__traits(isVirtualFunction, __traits(getMember, T, m)))
19         {
20             static foreach (fn; __traits(getOverloads, T, m))
21             {
22                 mixin("private ReturnType!fn delegate(Parameters!fn) " ~ fnAttr!fn ~ " " ~ dlgName!fn ~ ";");
23                 mixin("ReturnType!fn " ~ m ~ "(Parameters!fn args) " ~ fnAttr!fn ~ " { return " ~ dlgName!fn ~ "(args); }");
24             }
25         }
26     }
27 }
28 
29 ///
30 Like!T as(T, X)(auto ref X obj) if (is(T == interface))
31 {
32     Like!T ret;
33     
34     static foreach (m; [__traits(allMembers, T)])
35     {
36         static if (__traits(isVirtualFunction, __traits(getMember, T, m)))
37         {
38             static foreach (fn; __traits(getOverloads, T, m))
39             {
40                 mixin("ret." ~ ret.dlgName!fn ~ " = &obj."~m~";");
41             }
42         }
43     }
44 
45     return ret;
46 }
47 
48 version(unittest)
49 {
50     interface Foo
51     {
52     @safe:
53         void okda();
54     nothrow const:
55         int one();
56         int one(int x);
57         int two();
58     }
59 
60     static int useFoo(Like!Foo obj) @safe
61     {
62         obj.okda();
63         return obj.one() + obj.two() + obj.one(100);
64     }
65 }
66 
67 unittest
68 {
69     int k = 1;
70 
71     struct Bar
72     {
73         int a, b;
74     @safe:
75         void okda() { k = 3; }
76     nothrow const:
77         int one() { return a * 2 + k; }
78         int one(int x) { return a * x; }
79         int two() { return a + b; }
80     }
81 
82     assert(useFoo(Bar(2, 4).as!Foo) == 213);
83 }
84 
85 unittest
86 {
87     static class Bar : Foo
88     {
89         void okda() {}
90     override const:
91         int one() { return 5; }
92         int one(int x) { return x * 2; }
93         int two() { return 3; }
94     }
95 
96     assert(useFoo((new Bar).as!Foo) == 208);
97 }