1 /// 2 module aslike; 3 4 import std.traits; 5 import std.string : join, format; 6 import std.exception : enforce; 7 8 /// 9 struct Like(T) if (is(T == interface)) 10 { 11 private template dlgName(alias fn) { enum dlgName = "__dlg_" ~ fn.mangleof; } 12 private template fnAttr(alias fn) 13 { enum fnAttr = [__traits(getFunctionAttributes, fn)].join(" "); } 14 15 static foreach (m; [__traits(allMembers, T)]) 16 static if (__traits(isVirtualFunction, __traits(getMember, T, m))) 17 static foreach (fn; __traits(getOverloads, T, m)) 18 mixin(format!("private %1$s delegate(%2$s) %3$s %4$s;\n" ~ 19 "%1$s %5$s (%2$s args) %3$s { return %4$s(args); }") 20 ("ReturnType!fn", "Parameters!fn", fnAttr!fn, dlgName!fn, m)); 21 } 22 23 /// 24 Like!T as(T, bool nullCheck=true, X)(auto ref X obj) if (is(T == interface)) 25 { 26 Like!T ret; 27 28 static if (nullCheck && (is(X == interface) || is(X == class))) 29 enforce(obj !is null, "object is null"); 30 31 static foreach (m; [__traits(allMembers, T)]) 32 static if (__traits(isVirtualFunction, __traits(getMember, T, m))) 33 static foreach (fn; __traits(getOverloads, T, m)) 34 mixin("ret." ~ ret.dlgName!fn ~ " = &obj."~m~";"); 35 36 return ret; 37 } 38 39 version(unittest) 40 { 41 interface Foo 42 { 43 @safe: 44 void okda(); 45 nothrow const: 46 int one(); 47 int one(int x); 48 int two(); 49 } 50 51 static int useFoo(Like!Foo obj) @safe 52 { 53 obj.okda(); 54 return obj.one() + obj.two() + obj.one(100); 55 } 56 } 57 58 unittest 59 { 60 int k = 1; 61 62 struct Bar 63 { 64 int a, b; 65 @safe: 66 void okda() { k = 3; } 67 nothrow const: 68 int one() { return a * 2 + k; } 69 int one(int x) { return a * x; } 70 int two() { return a + b; } 71 } 72 73 assert(useFoo(Bar(2, 4).as!Foo) == 213); 74 } 75 76 unittest 77 { 78 static class Bar : Foo 79 { 80 void okda() {} 81 override const: 82 int one() { return 5; } 83 int one(int x) { return x * 2; } 84 int two() { return 3; } 85 } 86 87 assert(useFoo((new Bar).as!Foo) == 208); 88 } 89 90 unittest 91 { 92 static interface Foo2 { int func() @nogc; } 93 static void test(Like!Foo2 obj) @nogc { assert(obj.func() == 42); } 94 95 static class BarC : Foo2 96 { override int func() @nogc { return 42; } } 97 98 auto barC = new BarC; 99 (() @nogc { test(barC.as!(Foo2, false)); })(); 100 101 static struct BarS 102 { int func() @nogc { return 42; } } 103 104 BarS barS; 105 (() @nogc { test(barS.as!Foo2); })(); 106 107 import std : assertThrown; 108 BarC nullBarC; 109 assertThrown( nullBarC.as!Foo2 ); 110 } 111 112 @safe 113 unittest 114 { 115 static interface Foo3 { int func() @safe; } 116 static void test(Like!Foo3 obj) @safe { assert(obj.func() == 42); } 117 118 static class Bar : Foo3 119 { override int func() @nogc { return 42; } } 120 121 auto bar = new Bar; 122 (() @safe { test(bar.as!Foo3); })(); 123 }