1
2 module witchcraft.mixins.constructors;
3
4 mixin template WitchcraftConstructor(T)
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 }