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 }