1 2 module witchcraft.mixins.methods; 3 4 mixin template WitchcraftMethod(T) 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 if(typeid(instance.type) != typeid(TypeInfo_Class)) { 147 throw new Exception("The instance's type is not a class!"); 148 } 149 150 ClassInfo this_ = cast(ClassInfo) typeid(T); 151 ClassInfo other = cast(ClassInfo) instance.type; 152 153 // Ensure both types exist and can be converted. 154 if(!this_ || !other || !(_d_isbaseof(this_, other) || _d_isbaseof(other, this_))) 155 { 156 assert(0, "The instance can't cast to `" ~ T.stringof ~ "`."); 157 } 158 // FIXME: Needing refactor or cleanup -@zhangxueping at 4/17/2019, 6:21:23 PM 159 // The Variant's coerce can't handle a instance from a interface 160 Unqual!T obj = instance.coerce!(Unqual!T); 161 } 162 else static if(is(T)) 163 { 164 Unqual!T obj = instance.get!(Unqual!T); 165 } 166 else 167 { 168 alias obj = T; 169 } 170 171 static if(!is(ReturnType!method == void)) 172 { 173 mixin("auto result = __traits(getOverloads, obj, name)[overload](" ~ invokeString ~ ");"); 174 175 return Variant(result); 176 } 177 else 178 { 179 mixin("__traits(getOverloads, obj, name)[overload](" ~ invokeString ~ ");"); 180 181 return Variant(null); 182 } 183 } 184 185 @property 186 final bool isAccessible() const 187 { 188 return true; 189 } 190 191 @property 192 override bool isFinal() const 193 { 194 return __traits(isFinalFunction, method); 195 } 196 197 @property 198 override bool isOverride() const 199 { 200 return __traits(isOverrideFunction, method); 201 } 202 203 @property 204 override bool isStatic() const 205 { 206 return __traits(isStaticFunction, method); 207 } 208 209 @property 210 bool isVarArgs() const 211 { 212 return variadicFunctionStyle!method != Variadic.no; 213 } 214 } 215 }