1 module bolts.reflection.metaaggregate;
2 
3 import bolts.reflection.metafunction;
4 
5 static mixin template ModuleAggregateCommonCode()
6 {
7   import std.meta : staticMap, AliasSeq;
8   import bolts.reflection.metafunction;
9 
10   alias functions = staticMap!(collectMembers, __traits(allMembers, origin));
11 
12   private alias collectMembers(string name) = collectOverloads!(
13     name, 0, __traits(getOverloads, origin, name));
14 
15   private alias collectOverloads(string name, int index, Fun...) =
16     AliasSeq!(
17       Function!(Fun[0], source, name, index),
18       collectOverloads!(name, index + 1, Fun[1..$]));
19 
20   private alias collectOverloads(string name, int index) = AliasSeq!();
21 }
22 
23 template Aggregate(alias Aggregate_, string Source = __traits(identifier, Aggregate_))
24 {
25   alias origin = Aggregate_;
26   alias source = Source;
27   mixin ModuleAggregateCommonCode;
28 }
29 
30 unittest
31 {
32   import std.format;
33   import bolts.reflection.metafunction;
34   import std.traits; // needed by expansion or Function.returnType
35 
36   interface TheFullMonty
37   {
38     pure int foo() immutable;
39     @nogc @trusted nothrow ref int foo(out real, return ref int, lazy int) const;
40     @safe shared scope void foo(scope Object);
41   }
42 
43   template Mocker(alias F)
44   {
45     static if (is(F.returnType.origin == void)) {
46       enum Mocker = F.setBody!("").mixture;
47     } else static if (F.isRef) {
48       enum Mocker = F.setBody!(q{
49           static %s rv;
50           return rv;
51         }.format(F.returnType.mixture)).mixture;
52     } else {
53       enum Mocker = F.setBody!(q{
54           return %s.init;
55         }.format(F.returnType.mixture)).mixture;
56     }
57   }
58 
59   class Mock(Interface) : Interface
60   {
61     mixin(staticMap!(Mocker, Aggregate!Interface.functions));
62   }
63 
64   TheFullMonty mock = new Mock!TheFullMonty;
65   real x;
66   int i, l;
67   mock.foo(x, i, l++) = 1;
68   assert(mock.foo(x, i, l++) == 1);
69   assert(l == 0);
70 }