1 2 module witchcraft.mixins.methods; 3 4 mixin template WitchcraftMethod() 5 { 6 import witchcraft; 7 8 import std.meta; 9 import std.traits; 10 import std.variant; 11 12 static class MethodMixin(alias T, string name, size_t overload) : Method 13 { 14 private: 15 alias method = Alias!(__traits(getOverloads, T, name)[overload]); 16 alias Return = ReturnType!method; 17 18 public: 19 const(Attribute)[] getAttributes() const 20 { 21 alias attributes = AliasSeq!(__traits(getAttributes, method)); 22 auto values = new Attribute[attributes.length]; 23 24 foreach(index, attribute; attributes) 25 { 26 values[index] = new AttributeImpl!attribute; 27 } 28 29 return values; 30 } 31 32 const(Type) getDeclaringType() const 33 { 34 alias Parent = Alias!(__traits(parent, method)); 35 36 return inspect!Parent; 37 } 38 39 const(TypeInfo) getDeclaringTypeInfo() const 40 { 41 alias Parent = Alias!(__traits(parent, method)); 42 43 static if(__traits(compiles, typeid(Parent))) 44 { 45 return typeid(Parent); 46 } 47 else 48 { 49 return null; 50 } 51 } 52 53 string getName() const 54 { 55 return name; 56 } 57 58 string getFullName() const 59 { 60 return fullyQualifiedName!method; 61 } 62 63 const(Type)[] getParameterTypes() const 64 { 65 auto parameterTypes = new Type[Parameters!method.length]; 66 67 foreach(index, Parameter; Parameters!method) 68 { 69 parameterTypes[index] = inspect!Parameter; 70 } 71 72 return parameterTypes; 73 } 74 75 const(TypeInfo)[] getParameterTypeInfos() const 76 { 77 auto parameterTypeInfos = new TypeInfo[Parameters!method.length]; 78 79 foreach(index, Parameter; Parameters!method) 80 { 81 static if(__traits(compiles, typeid(Parameter))) 82 { 83 parameterTypeInfos[index] = typeid(Parameter); 84 } 85 } 86 87 return parameterTypeInfos; 88 } 89 90 string getProtection() const 91 { 92 return __traits(getProtection, method); 93 } 94 95 const(Type) getReturnType() const 96 { 97 return inspect!Return; 98 } 99 100 @property 101 const(TypeInfo) getReturnTypeInfo() const 102 { 103 static if(__traits(compiles, typeid(Return))) 104 { 105 return typeid(Return); 106 } 107 else 108 { 109 return null; 110 } 111 } 112 113 Variant invoke(Variant instance, Variant[] arguments...) const 114 { 115 import std.algorithm, std.conv, std.range, std..string; 116 117 alias Params = Parameters!method; 118 119 template NormalizeType(T) 120 { 121 static if(is(T == InoutOf!T)) 122 { 123 // HACK: There's no good way to remove inout-ness. 124 alias NormalizeType = void *; 125 } 126 else 127 { 128 alias NormalizeType = T; 129 } 130 } 131 132 enum variables = iota(0, Params.length) 133 .map!(i => "auto v%1$s = arguments[%1$s].get!(NormalizeType!(Params[%1$s]));".format(i)) 134 .joiner 135 .text; 136 137 enum invokeString = iota(0, Params.length) 138 .map!(i => "v%1$s".format(i)) 139 .joiner(", ") 140 .text; 141 142 mixin(variables); 143 144 static if(is(T == class)) 145 { 146 auto this_ = cast(ClassInfo) typeid(T); 147 auto other = cast(ClassInfo) instance.type; 148 149 // Ensure both types exist and can be converted. 150 if(!this_ || !other || !(_d_isbaseof(this_, other) || _d_isbaseof(other, this_))) 151 { 152 assert(0, "Instance isn't type of `" ~ T.stringof ~ "`."); 153 } 154 155 Unqual!T obj = instance.coerce!(Unqual!T); 156 } 157 else static if(is(T)) 158 { 159 Unqual!T obj = instance.get!(Unqual!T); 160 } 161 else 162 { 163 alias obj = T; 164 } 165 166 static if(!is(ReturnType!method == void)) 167 { 168 mixin("auto result = __traits(getOverloads, obj, name)[overload](" ~ invokeString ~ ");"); 169 170 return Variant(result); 171 } 172 else 173 { 174 mixin("__traits(getOverloads, obj, name)[overload](" ~ invokeString ~ ");"); 175 176 return Variant(null); 177 } 178 } 179 180 @property 181 final bool isAccessible() const 182 { 183 return true; 184 } 185 186 @property 187 override bool isFinal() const 188 { 189 return __traits(isFinalFunction, method); 190 } 191 192 @property 193 override bool isOverride() const 194 { 195 return __traits(isOverrideFunction, method); 196 } 197 198 @property 199 override bool isStatic() const 200 { 201 return __traits(isStaticFunction, method); 202 } 203 204 @property 205 bool isVarArgs() const 206 { 207 return variadicFunctionStyle!method != Variadic.no; 208 } 209 } 210 }