1 // Module to generate usefull TypeInfo 2 module mutils.type_info; 3 4 import std.algorithm : minElement; 5 import std.meta : AliasSeq; 6 import std.stdio; 7 import std.traits; 8 9 struct TypeData { 10 string name; 11 long size; 12 long aligment; 13 Field[] fields; 14 bool isCustomVector; 15 } 16 17 struct Field { 18 string name; 19 TypeData typeData; 20 string stringUda; 21 } 22 23 TypeData getTypeData(T)() { 24 TypeData data; 25 data.name = T.stringof; 26 data.size = T.sizeof; 27 data.aligment = T.alignof; 28 29 static if (is(T == struct)) { 30 alias TFields = Fields!T; 31 alias Names = FieldNameTuple!T; 32 foreach (i, F; TFields) { 33 alias TP = AliasSeq!(__traits(getAttributes, T.tupleof[i])); 34 string stringUda; 35 static if (is(typeof(TP[0]) == string)) { 36 stringUda = TP[0]; 37 38 } 39 data.fields ~= Field(Names[i], getTypeData!F, stringUda); 40 } 41 } 42 return data; 43 } 44 45 // Working with function overloads migh be painful so generate some data for it 46 47 // Maps to lua constant values 48 enum LuaType { 49 none = -1, 50 nil = 0, 51 boolean = 1, 52 lightuserdata = 2, 53 number = 3, 54 string = 4, 55 table = 5, 56 function_ = 6, 57 userdata = 7, 58 thread = 9 59 } 60 61 LuaType toLuaType(T)() { 62 static if (isIntegral!T || isFloatingPoint!T) { 63 return LuaType.number; 64 } else static if (is(T == string)) { 65 return LuaType..string; 66 } else { 67 return LuaType.userdata; 68 } 69 } 70 71 struct ParameterData { 72 TypeData typeData; 73 LuaType luaType; 74 bool hasDefaultValue; 75 } 76 77 struct OverloadData { 78 TypeData returnTypeData; 79 ParameterData[] parameters; 80 81 size_t minParametersNum() { 82 size_t parsNum = parameters.length; 83 foreach (p; parameters) { 84 parsNum -= p.hasDefaultValue; 85 } 86 return parsNum; 87 } 88 89 bool callableUsingArgsNum(size_t argsNum) { 90 return (argsNum >= minParametersNum && argsNum <= parameters.length); 91 } 92 } 93 94 struct ProcedureData { 95 string name; 96 OverloadData[] overloads; 97 98 size_t minParametersNum() { 99 100 return minElement!"a.minParametersNum"(overloads).minParametersNum; 101 } 102 103 } 104 105 // To generate data for normal function give module in place of StructType 106 ProcedureData getProcedureData(alias StructType, string procedureName)() { 107 ProcedureData procedureData; 108 procedureData.name = procedureName; 109 alias overloads = typeof(__traits(getOverloads, StructType, procedureName)); 110 foreach (overloadNum, overload; overloads) { 111 OverloadData overloadData; 112 113 alias FUN = overloads[overloadNum]; 114 alias Parms = Parameters!FUN; 115 alias ParmsDefault = ParameterDefaults!(__traits(getOverloads, 116 StructType, procedureName)[overloadNum]); 117 enum bool hasReturn = !is(ReturnType!FUN == void); 118 enum bool hasParms = Parms.length > 0; 119 120 overloadData.returnTypeData = getTypeData!(ReturnType!FUN); 121 122 foreach (ParNum, Par; Parms) { 123 ParameterData parameterData; 124 parameterData.typeData = getTypeData!Par; 125 parameterData.hasDefaultValue = (!is(ParmsDefault[ParNum] == void)); 126 parameterData.luaType = toLuaType!Par; 127 overloadData.parameters ~= parameterData; 128 } 129 130 procedureData.overloads ~= overloadData; 131 } 132 133 return procedureData; 134 } 135 136 unittest { 137 static struct Test { 138 int procA(int a, int b, int c = 10, int d = 10) { 139 return 0; 140 } 141 142 int procA(int a, int b = 100, int c = 10) { 143 return 0; 144 } 145 146 int proc() { 147 return 0; 148 } 149 150 int proc(int a) { 151 return 0; 152 } 153 154 int proc(int a, int b) { 155 return 0; 156 } 157 158 int proc(int a, int b = 100, int c = 10) { 159 return 0; 160 } 161 162 int proc(string a, int b) { 163 return 0; 164 } 165 166 int proc(int a, string b) { 167 return 0; 168 } 169 170 int proc(int a, string b, double c) { 171 return 0; 172 } 173 } 174 // Data for procedure 175 enum ProcedureData procedureDataA = getProcedureData!(Test, "procA"); 176 static assert(procedureDataA.overloads.length == 2); 177 static assert(procedureDataA.overloads[0].parameters.length == 4); 178 static assert(procedureDataA.overloads[1].parameters.length == 3); 179 static assert(procedureDataA.overloads[0].minParametersNum == 2); 180 static assert(procedureDataA.overloads[1].minParametersNum == 1); 181 static assert(procedureDataA.minParametersNum == 1); 182 static assert(procedureDataA.overloads[0].returnTypeData.name == "int"); 183 static assert(procedureDataA.overloads[0].parameters[0].typeData.name == "int"); 184 185 // Data for function 186 enum ProcedureData funcData = getProcedureData!(mutils.type_info, "func"); 187 static assert(funcData.overloads.length == 7); 188 static assert(funcData.overloads[0].parameters.length == 0); 189 static assert(funcData.overloads[1].parameters.length == 1); 190 static assert(funcData.overloads[2].parameters.length == 2); 191 static assert(funcData.overloads[3].parameters.length == 3); 192 static assert(funcData.overloads[4].parameters.length == 2); 193 static assert(funcData.overloads[5].parameters.length == 2); 194 static assert(funcData.overloads[6].parameters.length == 3); 195 static assert(funcData.overloads[3].minParametersNum == 1); 196 static assert(funcData.minParametersNum == 0); 197 static assert(funcData.overloads[0].returnTypeData.name == "int"); 198 static assert(funcData.overloads[1].parameters[0].typeData.name == "int"); 199 } 200 201 // Used only for tests 202 private: 203 int func() { 204 return 0; 205 } 206 207 int func(int a) { 208 return 0; 209 } 210 211 int func(int a, int b) { 212 return 0; 213 } 214 215 int func(int a, int b = 100, int c = 10) { 216 return 0; 217 } 218 219 int func(string a, int b) { 220 return 0; 221 } 222 223 int func(int a, string b) { 224 return 0; 225 } 226 227 int func(int a, string b, double c) { 228 return 0; 229 }