1 module introspection.type; 2 3 import std.traits; 4 import introspection.manifestConstant; 5 6 version(unittest) { 7 import fluent.asserts; 8 } 9 10 /// 11 template ArrayValueType(T : T[]) { alias ArrayValueType = T; } 12 13 14 /// Stores information about types 15 struct Type { 16 /// The type name, how it was defined or used in the source code 17 string name; 18 19 /// The type name without qualifiers 20 string unqualName; 21 22 /// 23 string fullyQualifiedName; 24 25 /// The name of the module where the symbol is defined; 26 string module_; 27 28 /// 29 bool isStruct; 30 31 /// 32 bool isClass; 33 34 /// 35 bool isInterface; 36 37 /// 38 bool isUnion; 39 40 /// 41 bool isArray; 42 43 /// 44 bool isEnum; 45 46 /// 47 bool isAssociativeArray; 48 49 /// The keys used by the array 50 string keyType; 51 52 /// The array values 53 string valueType; 54 55 /// true if it is scalar type or void 56 bool isBasicType; 57 58 /// true if it is a type defined by the compiler 59 bool isBuiltinType; 60 61 /// true if it has `const` qualifier 62 bool isConst; 63 64 /// true if it has `inout` qualifier 65 bool isInout; 66 67 /// true if it has `immutable` qualifier 68 bool isImmutable; 69 70 /// true if it has `shared` qualifier 71 bool isShared; 72 73 /// true if it is manifest constant. eg. `enum name = "test";` 74 bool isManifestConstant; 75 } 76 77 /// Describe a type 78 Type describeType(T)() { 79 Type type; 80 81 type.name = T.stringof; 82 type.unqualName = Unqual!T.stringof; 83 84 static if(__traits(compiles, fullyQualifiedName!T)) { 85 type.fullyQualifiedName = fullyQualifiedName!T; 86 } 87 88 static if(__traits(compiles, moduleName!T)) { 89 type.module_ = moduleName!T; 90 } 91 92 type.isBasicType = isBasicType!T; 93 type.isBuiltinType = isBuiltinType!T; 94 95 static if(is(T == struct)) { 96 type.isStruct = true; 97 } 98 99 static if(is(T == class)) { 100 type.isClass = true; 101 } 102 103 static if(is(T == union)) { 104 type.isUnion = true; 105 } 106 107 static if(is(T == interface)) { 108 type.isInterface = true; 109 } 110 111 static if(is(T == enum)) { 112 type.isEnum = true; 113 type.isBasicType = false; 114 type.isBuiltinType = false; 115 } 116 117 static if(isArray!T) { 118 type.isArray = true; 119 type.keyType = "size_t"; 120 type.valueType = ArrayValueType!T.stringof; 121 } 122 123 static if(isAssociativeArray!T) { 124 type.isAssociativeArray = true; 125 type.keyType = KeyType!T.stringof; 126 type.valueType = ValueType!T.stringof; 127 } 128 129 static if(is(T == const)) { 130 type.isConst = true; 131 } 132 133 static if(is(T == inout)) { 134 type.isInout = true; 135 } 136 137 static if(is(T == immutable)) { 138 type.isImmutable = true; 139 } 140 141 static if(is(T == shared)) { 142 type.isShared = true; 143 } 144 145 static if(is(typeof(T)) && !is(typeof(&T))) { 146 type.isManifestConstant = true; 147 } 148 149 return type; 150 } 151 152 /// ditto 153 Type describeType(alias T)() if(!is(T == enum)) { 154 auto type = describeType!(typeof(T)); 155 156 static if(isManifestConstant!T) { 157 type.isManifestConstant = true; 158 } 159 160 return type; 161 } 162 163 164 /// It should describe an int 165 unittest { 166 auto result = describeType!int; 167 168 result.name.should.equal("int"); 169 result.unqualName.should.equal("int"); 170 result.fullyQualifiedName.should.equal("int"); 171 172 result.isBasicType.should.equal(true); 173 result.isBuiltinType.should.equal(true); 174 result.isConst.should.equal(false); 175 result.isInout.should.equal(false); 176 result.isImmutable.should.equal(false); 177 result.isShared.should.equal(false); 178 } 179 180 /// It should describe an int at compile time 181 unittest { 182 enum result = describeType!int; 183 184 result.name.should.equal("int"); 185 result.unqualName.should.equal("int"); 186 } 187 188 /// It should describe a const int 189 unittest { 190 auto result = describeType!(const(int)); 191 192 result.name.should.equal("const(int)"); 193 result.unqualName.should.equal("int"); 194 195 result.isBasicType.should.equal(true); 196 result.isBuiltinType.should.equal(true); 197 result.isConst.should.equal(true); 198 result.isInout.should.equal(false); 199 result.isImmutable.should.equal(false); 200 result.isShared.should.equal(false); 201 } 202 203 /// It should describe an inout int 204 unittest { 205 auto result = describeType!(inout(int)); 206 207 result.name.should.equal("inout(int)"); 208 result.unqualName.should.equal("int"); 209 210 result.isBasicType.should.equal(true); 211 result.isBuiltinType.should.equal(true); 212 result.isConst.should.equal(false); 213 result.isInout.should.equal(true); 214 result.isImmutable.should.equal(false); 215 result.isShared.should.equal(false); 216 } 217 218 /// It should describe an immutable int 219 unittest { 220 auto result = describeType!(immutable(int)); 221 222 result.name.should.equal("immutable(int)"); 223 result.unqualName.should.equal("int"); 224 225 result.isBasicType.should.equal(true); 226 result.isBuiltinType.should.equal(true); 227 result.isConst.should.equal(false); 228 result.isInout.should.equal(false); 229 result.isImmutable.should.equal(true); 230 result.isShared.should.equal(false); 231 } 232 233 /// It should describe a shared int 234 unittest { 235 auto result = describeType!(shared(int)); 236 237 result.name.should.equal("shared(int)"); 238 result.unqualName.should.equal("int"); 239 240 result.isBasicType.should.equal(true); 241 result.isBuiltinType.should.equal(true); 242 result.isConst.should.equal(false); 243 result.isInout.should.equal(false); 244 result.isImmutable.should.equal(false); 245 result.isShared.should.equal(true); 246 } 247 248 /// It should describe a int pointer 249 unittest { 250 auto result = describeType!(int*); 251 252 result.name.should.equal("int*"); 253 result.unqualName.should.equal("int*"); 254 255 result.isBasicType.should.equal(false); 256 result.isBuiltinType.should.equal(false); 257 result.isConst.should.equal(false); 258 result.isInout.should.equal(false); 259 result.isImmutable.should.equal(false); 260 result.isShared.should.equal(false); 261 } 262 263 /// It should describe a manifest constant 264 unittest { 265 enum a = "value"; 266 auto result = describeType!(a); 267 268 result.name.should.equal("string"); 269 result.unqualName.should.equal("string"); 270 271 result.isBasicType.should.equal(false); 272 result.isBuiltinType.should.equal(true); 273 result.isConst.should.equal(false); 274 result.isInout.should.equal(false); 275 result.isImmutable.should.equal(false); 276 result.isShared.should.equal(false); 277 result.isManifestConstant.should.equal(true); 278 } 279 280 /// It shuld describe an array of ints 281 unittest { 282 auto result = describeType!(int[]); 283 284 result.name.should.equal("int[]"); 285 result.unqualName.should.equal("int[]"); 286 287 result.isArray.should.equal(true); 288 result.keyType.should.equal("size_t"); 289 result.valueType.should.equal("int"); 290 } 291 292 /// It shuld describe an array of strings 293 unittest { 294 auto result = describeType!(string[]); 295 296 result.name.should.equal("string[]"); 297 result.unqualName.should.equal("string[]"); 298 299 result.isArray.should.equal(true); 300 result.keyType.should.equal("size_t"); 301 result.valueType.should.equal("string"); 302 } 303 304 /// It shuld describe an assoc array of ints 305 unittest { 306 auto result = describeType!(int[string]); 307 308 result.name.should.equal("int[string]"); 309 result.unqualName.should.equal("int[string]"); 310 311 result.isArray.should.equal(false); 312 result.isAssociativeArray.should.equal(true); 313 result.keyType.should.equal("string"); 314 result.valueType.should.equal("int"); 315 } 316 317 /// It shuld describe an assoc array of strings 318 unittest { 319 auto result = describeType!(string[string]); 320 321 result.name.should.equal("string[string]"); 322 result.unqualName.should.equal("string[string]"); 323 324 result.isArray.should.equal(false); 325 result.isAssociativeArray.should.equal(true); 326 result.keyType.should.equal("string"); 327 result.valueType.should.equal("string"); 328 } 329 330 /// It shuld describe a nested array 331 unittest { 332 auto result = describeType!(int[ulong][][ulong]); 333 334 result.name.should.equal("int[ulong][][ulong]"); 335 result.unqualName.should.equal("int[ulong][][ulong]"); 336 337 result.isArray.should.equal(false); 338 result.isAssociativeArray.should.equal(true); 339 result.keyType.should.equal("ulong"); 340 result.valueType.should.equal("int[ulong][]"); 341 } 342 343 /// It should describe a struct 344 unittest { 345 struct Test {} 346 347 auto result = describeType!Test; 348 349 result.name.should.equal("Test"); 350 result.unqualName.should.equal("Test"); 351 result.fullyQualifiedName.should.equal("introspection.type.__unittest_L344_C1.Test"); 352 353 result.isStruct.should.equal(true); 354 result.isBasicType.should.equal(false); 355 result.isBuiltinType.should.equal(false); 356 result.isConst.should.equal(false); 357 result.isInout.should.equal(false); 358 result.isImmutable.should.equal(false); 359 result.isShared.should.equal(false); 360 } 361 362 /// It should describe a class 363 unittest { 364 class Test {} 365 366 auto result = describeType!Test; 367 368 result.name.should.equal("Test"); 369 result.unqualName.should.equal("Test"); 370 371 result.isStruct.should.equal(false); 372 result.isClass.should.equal(true); 373 result.isBasicType.should.equal(false); 374 result.isBuiltinType.should.equal(false); 375 result.isConst.should.equal(false); 376 result.isInout.should.equal(false); 377 result.isImmutable.should.equal(false); 378 result.isShared.should.equal(false); 379 } 380 381 /// It should describe an union 382 unittest { 383 union Test {} 384 385 auto result = describeType!Test; 386 387 result.name.should.equal("Test"); 388 result.unqualName.should.equal("Test"); 389 390 result.isStruct.should.equal(false); 391 result.isClass.should.equal(false); 392 result.isUnion.should.equal(true); 393 result.isBasicType.should.equal(false); 394 result.isBuiltinType.should.equal(false); 395 result.isConst.should.equal(false); 396 result.isInout.should.equal(false); 397 result.isImmutable.should.equal(false); 398 result.isShared.should.equal(false); 399 } 400 401 /// It should describe an interface 402 unittest { 403 interface Test {} 404 405 auto result = describeType!Test; 406 407 result.name.should.equal("Test"); 408 result.unqualName.should.equal("Test"); 409 410 result.isStruct.should.equal(false); 411 result.isClass.should.equal(false); 412 result.isUnion.should.equal(false); 413 result.isInterface.should.equal(true); 414 result.isBasicType.should.equal(false); 415 result.isBuiltinType.should.equal(false); 416 result.isConst.should.equal(false); 417 result.isInout.should.equal(false); 418 result.isImmutable.should.equal(false); 419 result.isShared.should.equal(false); 420 } 421 422 /// It should describe an enum 423 unittest { 424 enum Test { 425 a,b,c 426 } 427 428 auto result = describeType!Test; 429 430 result.name.should.equal("Test"); 431 result.unqualName.should.equal("Test"); 432 result.module_.should.equal("introspection.type"); 433 434 result.isStruct.should.equal(false); 435 result.isClass.should.equal(false); 436 result.isUnion.should.equal(false); 437 result.isInterface.should.equal(false); 438 result.isEnum.should.equal(true); 439 result.isBasicType.should.equal(false); 440 result.isBuiltinType.should.equal(false); 441 result.isConst.should.equal(false); 442 result.isInout.should.equal(false); 443 result.isImmutable.should.equal(false); 444 result.isShared.should.equal(false); 445 }