1 module ut.meta.traits; 2 3 4 import ut; 5 import mirror.meta.reflection; 6 import mirror.meta.traits; 7 import std.meta: AliasSeq; 8 9 10 @("isEnum") 11 @safe pure unittest { 12 static import modules.types; 13 import std.meta: Filter, AliasSeq; 14 15 alias mod = Module!"modules.types"; 16 alias aggregates = mod.Aggregates; 17 alias enums = Filter!(isEnum, aggregates); 18 shouldEqual!(enums, AliasSeq!(modules.types.Enum, modules.types.Char)); 19 } 20 21 22 @("isStruct") 23 @safe pure unittest { 24 static import modules.types; 25 import std.meta: Filter, AliasSeq; 26 27 alias mod = Module!"modules.types"; 28 alias aggregates = mod.Aggregates; 29 alias structs = Filter!(isStruct, aggregates); 30 static assert(is(structs == 31 AliasSeq!( 32 modules.types.String, 33 modules.types.Point, 34 modules.types.Inner1, 35 modules.types.EvenInner, 36 modules.types.Inner2, 37 modules.types.Outer, 38 ) 39 ), 40 structs.stringof); 41 } 42 43 44 @("isInterface") 45 @safe pure unittest { 46 static import modules.types; 47 import std.meta: Filter, AliasSeq; 48 49 alias mod = Module!"modules.types"; 50 alias aggregates = mod.Aggregates; 51 alias interfaces = Filter!(isInterface, aggregates); 52 static assert(is(interfaces == AliasSeq!(modules.types.Interface)), interfaces.stringof); 53 } 54 55 56 @("isClass") 57 @safe pure unittest { 58 static import modules.types; 59 import std.meta: Filter, AliasSeq; 60 61 alias mod = Module!"modules.types"; 62 alias aggregates = mod.Aggregates; 63 alias classes = Filter!(isClass, aggregates); 64 alias expected = AliasSeq!( 65 modules.types.Class, 66 modules.types.AbstractClass, 67 modules.types.MiddleClass, 68 modules.types.LeafClass, 69 ); 70 static assert(is(classes == expected), classes.stringof); 71 } 72 73 74 @("isOOP") 75 @safe pure unittest { 76 static import modules.types; 77 import std.meta: Filter, AliasSeq; 78 79 alias mod = Module!"modules.types"; 80 alias aggregates = mod.Aggregates; 81 alias classes = Filter!(isOOP, aggregates); 82 alias expected = AliasSeq!( 83 modules.types.Class, 84 modules.types.Interface, 85 modules.types.AbstractClass, 86 modules.types.MiddleClass, 87 modules.types.LeafClass, 88 ); 89 static assert(is(classes == expected), classes.stringof); 90 } 91 92 93 @("FundamentalType.scalar") 94 @safe pure unittest { 95 static assert(is(FundamentalType!int == int)); 96 static assert(is(FundamentalType!double == double)); 97 static struct Foo { } 98 static assert(is(FundamentalType!Foo == Foo)); 99 } 100 101 102 @("FundamentalType.array") 103 @safe pure unittest { 104 static assert(is(FundamentalType!(int[]) == int)); 105 static assert(is(FundamentalType!(int[][]) == int)); 106 static assert(is(FundamentalType!(int[][][]) == int)); 107 108 static assert(is(FundamentalType!(double[]) == double)); 109 static assert(is(FundamentalType!(double[][]) == double)); 110 111 static assert(is(FundamentalType!string == immutable char)); 112 static assert(is(FundamentalType!(string[]) == immutable char)); 113 114 static struct Foo { } 115 static assert(is(FundamentalType!(Foo[]) == Foo)); 116 static assert(is(FundamentalType!(Foo[][]) == Foo)); 117 } 118 119 120 @("FundamentalType.pointer") 121 @safe pure unittest { 122 static assert(is(FundamentalType!(int*) == int)); 123 static assert(is(FundamentalType!(int**) == int)); 124 static assert(is(FundamentalType!(int***) == int)); 125 126 static assert(is(FundamentalType!(double*) == double)); 127 static assert(is(FundamentalType!(double**) == double)); 128 129 static assert(is(FundamentalType!(string*) == immutable char)); 130 static assert(is(FundamentalType!(string**) == immutable char)); 131 132 static struct Foo { } 133 static assert(is(FundamentalType!(Foo*) == Foo)); 134 static assert(is(FundamentalType!(Foo**) == Foo)); 135 } 136 137 138 @("RecursiveFieldTypes.scalar") 139 @safe pure unittest { 140 static assert(is(RecursiveFieldTypes!int == int)); 141 static assert(is(RecursiveFieldTypes!double == double)); 142 } 143 144 145 @("RecursiveFieldTypes.udt.flat") 146 @safe pure unittest { 147 148 static struct Foo { 149 int i; 150 double d; 151 } 152 153 shouldEqual!(RecursiveFieldTypes!Foo, AliasSeq!(int, double)); 154 } 155 156 157 @("RecursiveFieldTypes.udt.nested") 158 @safe pure unittest { 159 160 static struct Inner0 { 161 int i; 162 double d; 163 } 164 165 static struct Inner1 { 166 double d; 167 string s; 168 } 169 170 static struct Mid { 171 Inner0 inner0; 172 Inner1 inner1; 173 } 174 175 static struct Outer { 176 Mid mid; 177 byte b; 178 float func(float, float); 179 180 @property static Outer max() @safe pure nothrow @nogc { 181 return Outer(); 182 } 183 } 184 185 shouldEqual!(RecursiveFieldTypes!Outer, 186 AliasSeq!(Mid, Inner0, int, double, Inner1, string, byte)); 187 } 188 189 190 @("RecursiveFieldTypes.udt.Date") 191 @safe pure unittest { 192 193 import std.datetime: Date, Month; 194 195 static struct Struct { 196 int i; 197 Date date; 198 } 199 200 shouldEqual!(RecursiveFieldTypes!Struct, 201 AliasSeq!(int, Date, short, Month, ubyte)); 202 } 203 204 205 @("RecursiveFieldTypes.udt.DateTime") 206 @safe pure unittest { 207 208 import std.datetime: Date, DateTime, Month, TimeOfDay; 209 210 static struct Struct { 211 int i; 212 DateTime date; 213 } 214 215 shouldEqual!(RecursiveFieldTypes!Struct, 216 AliasSeq!(int, DateTime, Date, short, Month, ubyte, TimeOfDay)); 217 } 218 219 220 @("RecursiveFieldTypes.udt.composite.struct") 221 @safe pure unittest { 222 223 static struct Struct { 224 Struct* child; 225 } 226 227 shouldEqual!(RecursiveFieldTypes!Struct, Struct*); 228 } 229 230 231 @("RecursiveFieldTypes.udt.composite.class.simple") 232 @safe pure unittest { 233 234 static class Class { 235 Class child; 236 } 237 238 shouldEqual!(RecursiveFieldTypes!Class, Class); 239 } 240 241 242 @("RecursiveFieldTypes.udt.composite.class.multiple") 243 @safe pure unittest { 244 245 shouldEqual!(RecursiveFieldTypes!RecursiveClass0, 246 AliasSeq!(RecursiveClass1, RecursiveClass2)); 247 } 248 249 250 private class RecursiveClass0 { 251 RecursiveClass1 child; 252 } 253 254 private class RecursiveClass1 { 255 RecursiveClass2 child; 256 } 257 258 private class RecursiveClass2 { 259 RecursiveClass0 child; 260 } 261 262 263 @("RecursiveFieldTypes.udt.composite.array") 264 @safe pure unittest { 265 266 static struct Point(T) { 267 T x, y; 268 } 269 270 struct Inner1(T) { 271 Point!T point; 272 T value; 273 } 274 275 struct EvenInner(T) { 276 T value; 277 } 278 279 struct Inner2(T) { 280 EvenInner!T evenInner; 281 } 282 283 static struct Outer(T) { 284 Inner1!T[] inner1s; 285 Inner2!T inner2; 286 } 287 288 // pragma(msg, RecursiveFieldTypes!(Outer!double)); 289 shouldEqual!(RecursiveFieldTypes!(Outer!double), 290 AliasSeq!(Inner1!double[], Point!double, double, Inner2!double, EvenInner!double)); 291 } 292 293 294 @("RecursiveFieldTypes.SocketOSException") 295 @safe @nogc pure unittest { 296 import std.socket: SocketOSException; 297 alias types = RecursiveFieldTypes!SocketOSException; 298 //pragma(msg, types); 299 shouldEqual!(types, AliasSeq!int); 300 } 301 302 303 @("isProperty.struct") 304 @safe @nogc pure unittest { 305 306 static struct Struct { 307 int _i; 308 @property int i(); 309 @property void i(int i); 310 int foo(double d); 311 } 312 313 static assert(isProperty!(__traits(getOverloads, Struct, "i")[1])); 314 static assert(isProperty!(__traits(getOverloads, Struct, "i")[1])); 315 static assert(!isProperty!(Struct.foo)); 316 } 317 318 319 @("isProperty.class") 320 @safe @nogc pure unittest { 321 322 static class Class { 323 int _i; 324 @property int i() { return _i; } 325 @property void i(int i) { _i = i; } 326 int foo(double d) { return i * 2; } 327 } 328 329 static assert(isProperty!(__traits(getOverloads, Class, "i")[1])); 330 static assert(isProperty!(__traits(getOverloads, Class, "i")[1])); 331 static assert(!isProperty!(Class.foo)); 332 } 333 334 335 @("MemberFunctionsByOverload.struct") 336 @safe @nogc pure unittest { 337 338 static struct Struct { 339 private int _i; 340 @property int i(); 341 @property void i(int i); 342 int foo(double d); 343 string bar(int i); 344 } 345 346 //pragma(msg, "MemberFunctionsByOverload.struct: ", MemberFunctionsByOverload!Struct.stringof); 347 348 shouldEqual!( 349 MemberFunctionsByOverload!Struct, 350 AliasSeq!( 351 __traits(getOverloads, Struct, "i")[0], 352 __traits(getOverloads, Struct, "i")[1], 353 Struct.foo, 354 Struct.bar, 355 ) 356 ); 357 } 358 359 360 @("MemberFunctionsByOverload.class.simple") 361 @safe @nogc pure unittest { 362 363 static class Class { 364 private int _i; 365 @property int i() { return _i; } 366 @property void i(int i) { _i = i; } 367 int foo(double d) { return cast(int) (d * 2); } 368 string bar(int i) { return "foobar"; } 369 } 370 371 // pragma(msg, "MemberFunctionsByOverload.class: ", MemberFunctionsByOverload!Class.stringof); 372 373 shouldEqual!( 374 MemberFunctionsByOverload!Class, 375 AliasSeq!( 376 __traits(getOverloads, Class, "i")[0], 377 __traits(getOverloads, Class, "i")[1], 378 Class.foo, 379 Class.bar, 380 ) 381 ); 382 } 383 384 385 @("MemberFunctionsByOverload.std.stdio.File") 386 @safe @nogc pure unittest { 387 import std.stdio: File; 388 alias functions = MemberFunctionsByOverload!File; 389 static assert(functions.length > 0); 390 } 391 392 @("MemberFunctionsByOverload.CtorProtectionsStruct") 393 @safe @nogc pure unittest { 394 import modules.issues: CtorProtectionsStruct; 395 alias functions = MemberFunctionsByOverload!CtorProtectionsStruct; 396 //pragma(msg, functions.stringof); 397 static assert(functions.length == 1); // the only public constructor 398 } 399 400 401 @("PublicMembers.std.socket") 402 @safe @nogc pure unittest { 403 import std.socket; 404 alias members = PublicMembers!(std.socket); 405 } 406 407 408 409 @("isStaticMemberFunction") 410 @safe @nogc pure unittest { 411 static struct Struct { 412 int foo(); 413 static int bar(); 414 } 415 416 static void fun() {} 417 418 static assert(!isStaticMemberFunction!(Struct.foo)); 419 static assert( isStaticMemberFunction!(Struct.bar)); 420 static assert(!isStaticMemberFunction!fun); 421 static assert(!isStaticMemberFunction!staticGlobalFunc); 422 } 423 424 425 static void staticGlobalFunc() { 426 427 } 428 429 430 @("BinaryOperators") 431 @safe @nogc pure unittest { 432 433 static struct Number { 434 int i; 435 Number opBinary(string op)(Number other) if(op == "+") { 436 return Number(i + other.i); 437 } 438 Number opBinary(string op)(Number other) if(op == "-") { 439 return Number(i - other.i); 440 } 441 Number opBinaryRight(string op)(int other) if(op == "+") { 442 return Number(i + other); 443 } 444 } 445 446 static assert( 447 [BinaryOperators!Number] == 448 [ 449 BinaryOperator("+", BinOpDir.left | BinOpDir.right), 450 BinaryOperator("-", BinOpDir.left), 451 ] 452 ); 453 } 454 455 456 @("UnaryOperators") 457 @safe pure unittest { 458 459 static struct Struct { 460 int opUnary(string op)() if(op == "+") { return 42; } 461 int opUnary(string op)() if(op == "~") { return 33; } 462 } 463 464 static assert([UnaryOperators!Struct] == ["+", "~"]); 465 } 466 467 468 @("AssignOperators") 469 @safe pure unittest { 470 471 static struct Number { 472 int i; 473 Number opOpAssign(string op)(Number other) if(op == "+") { 474 return Number(i + other.i); 475 } 476 Number opOpAssign(string op)(Number other) if(op == "-") { 477 return Number(i - other.i); 478 } 479 Number opOpAssignRight(string op)(int other) if(op == "+") { 480 return Number(i + other); 481 } 482 } 483 484 static assert([AssignOperators!Number] == ["+", "-"]); 485 } 486 487 488 @("NumDefaultParameters") 489 @safe pure unittest { 490 491 static void none0(); 492 static assert(NumDefaultParameters!none0 == 0); 493 494 static void none1(int i); 495 static assert(NumDefaultParameters!none1 == 0); 496 497 static void one(int i, double d = 33.3); 498 static assert(NumDefaultParameters!one == 1); 499 500 static void two(int i, double d = 33.3, int j = 42); 501 static assert(NumDefaultParameters!two == 2); 502 } 503 504 505 @("NumRequiredParameters") 506 @safe pure unittest { 507 508 static void none(); 509 static assert(NumRequiredParameters!none == 0); 510 511 static void one0(int i, double d = 33.3); 512 static assert(NumRequiredParameters!one0 == 1); 513 514 static void one1(int i, double d = 33.3, int j = 42); 515 static assert(NumRequiredParameters!one1 == 1); 516 517 static void two(int i, string s, double d = 33.3, int j = 42); 518 static assert(NumRequiredParameters!two == 2); 519 } 520 521 522 @("Parameters.default.function.ptr") 523 @safe pure unittest { 524 static string defaultFormatter(int) { return "oops"; } 525 static void func(string function(int) @trusted errorFormatter = &defaultFormatter); 526 alias params = Parameters!func; 527 } 528 529 530 @("isMutableSymbol") 531 @safe pure unittest { 532 static import modules.variables; 533 static assert( isMutableSymbol!(modules.variables.gInt)); 534 static assert(!isMutableSymbol!(modules.variables.gDouble)); 535 static assert( isMutableSymbol!(modules.variables.gStruct)); 536 static assert(!isMutableSymbol!(modules.variables.CONSTANT_INT)); 537 static assert(!isMutableSymbol!(modules.variables.CONSTANT_STRING)); 538 static assert(!isMutableSymbol!(modules.variables.gImmutableInt)); 539 } 540 541 542 @("isVariable") 543 @safe pure unittest { 544 static import modules.variables; 545 546 alias member(string name) = MemberFromName!(modules.variables, name); 547 548 static assert( isVariable!(member!"gInt")); 549 static assert(!isVariable!(member!"Struct")); 550 static assert(!isVariable!(member!"templateFunction")); 551 } 552 553 554 @("Fields.struct.0") 555 @safe pure unittest { 556 557 static struct Struct { 558 int i; 559 string s; 560 } 561 562 shouldEqual!( 563 Fields!Struct, 564 Field!(int, "i"), Field!(string, "s"), 565 ); 566 } 567 568 569 @("Fields.struct.1") 570 @safe pure unittest { 571 572 import mirror.trait_enums: Protection; 573 574 static struct Struct { 575 double d; 576 byte b; 577 private int i; 578 string s; 579 } 580 581 shouldEqual!( 582 Fields!Struct, 583 584 Field!(double, "d"), 585 Field!(byte, "b"), 586 Field!(int, "i", Protection.private_), 587 Field!(string, "s"), 588 ); 589 } 590 591 592 @("Fields.class") 593 @safe pure unittest { 594 595 static abstract class Abstract {} 596 597 static class Base: Abstract { 598 int i; 599 } 600 601 static class Child: Base { 602 string s; 603 this(string s) { this.s = s ~ "_suffix"; } 604 } 605 606 // pragma(msg, Fields!Child); 607 608 shouldEqual!( 609 Fields!Child, 610 Field!(string, "s"), Field!(int, "i"), 611 ); 612 }