1 
2 module witchcraft.mixins.constructors;
3 
4 mixin template WitchcraftConstructor()
5 {
6     import witchcraft;
7 
8     import std.algorithm;
9     import std.conv;
10     import std.meta;
11     import std.range;
12     import std..string;
13     import std.traits;
14     import std.variant;
15 
16     static class ConstructorMixin(alias T, size_t overload) : Constructor
17     {
18     private:
19         alias method = Alias!(__traits(getOverloads, T, "__ctor")[overload]);
20         alias Return = ReturnType!method;
21 
22     public:
23         const(Attribute)[] getAttributes() const
24         {
25             alias attributes = AliasSeq!(__traits(getAttributes, method));
26             auto values = new Attribute[attributes.length];
27 
28             foreach(index, attribute; attributes)
29             {
30                 values[index] = new AttributeImpl!attribute;
31             }
32 
33             return values;
34         }
35 
36         const(Type) getDeclaringType() const
37         {
38             alias Parent = Alias!(__traits(parent, method));
39 
40             return inspect!Parent;
41         }
42 
43         const(TypeInfo) getDeclaringTypeInfo() const
44         {
45             alias Parent = Alias!(__traits(parent, method));
46 
47             static if(__traits(compiles, typeid(Parent)))
48             {
49                 return typeid(Parent);
50             }
51             else
52             {
53                 return null;
54             }
55         }
56 
57         string getFullName() const
58         {
59             return fullyQualifiedName!method;
60         }
61 
62         const(Type)[] getParameterTypes() const
63         {
64             auto parameterTypes = new Type[Parameters!method.length];
65 
66             foreach(index, Parameter; Parameters!method)
67             {
68                 parameterTypes[index] = inspect!Parameter;
69             }
70 
71             return parameterTypes;
72         }
73 
74         const(TypeInfo)[] getParameterTypeInfos() const
75         {
76             auto parameterTypeInfos = new TypeInfo[Parameters!method.length];
77 
78             foreach(index, Parameter; Parameters!method)
79             {
80                 static if(__traits(compiles, typeid(Parameter)))
81                 {
82                     parameterTypeInfos[index] = typeid(Parameter);
83                 }
84             }
85 
86             return parameterTypeInfos;
87         }
88 
89         string getProtection() const
90         {
91             return __traits(getProtection, method);
92         }
93 
94         const(Type) getReturnType() const
95         {
96             return inspect!Return;
97         }
98 
99         @property
100         const(TypeInfo) getReturnTypeInfo() const
101         {
102             static if(__traits(compiles, typeid(Return)))
103             {
104                 return typeid(Return);
105             }
106             else
107             {
108                 return null;
109             }
110         }
111 
112         static if(isAbstractClass!T)
113         {
114             Variant invoke(Variant instance, Variant[] arguments...) const
115             {
116                 assert(0, T.stringof ~ " is abstract.");
117             }
118         }
119         else
120         {
121             Variant invoke(Variant instance, Variant[] arguments...) const
122             {
123                 import std.algorithm, std.conv, std.range, std..string;
124 
125                 alias Params = Parameters!method;
126 
127                 enum variables = iota(0, Params.length)
128                     .map!(i => "auto v%1$s = arguments[%1$s].get!(Params[%1$s]);".format(i))
129                     .joiner.text;
130 
131                 enum invokeString = iota(0, Params.length)
132                     .map!(i => "v%s".format(i))
133                     .joiner(", ").text;
134 
135                 mixin(variables);
136                 mixin("Params args = AliasSeq!(" ~ invokeString ~ ");");
137 
138                 static if(is(T == class))
139                 {
140                     return Variant(new T(args));
141                 }
142                 else
143                 {
144                     return Variant(T(args));
145                 }
146             }
147         }
148 
149         @property
150         final bool isAccessible() const
151         {
152             return true;
153         }
154 
155         @property
156         bool isVarArgs() const
157         {
158             return variadicFunctionStyle!method != Variadic.no;
159         }
160     }
161 }