1 module rpui.traits;
2 
3 import std.traits : hasUDA, getUDAs, isFunction, isType, isAggregateType;
4 
5 template getSymbolsNamesByUDA(alias symbol, alias attribute) {
6     import std.format : format;
7     import std.meta : AliasSeq, Filter;
8 
9     // filtering inaccessible members
10     enum noInaccessibleMembers(string name) = (__traits(compiles, __traits(getMember, symbol, name)));
11     alias withoutInaccessibleMembers = Filter!(noInaccessibleMembers, __traits(allMembers, symbol));
12 
13     // filtering out nested class context
14     enum noThisMember(string name) = (name != "this");
15     alias membersWithoutNestedCC = Filter!(noThisMember, withoutInaccessibleMembers);
16 
17     // filtering not compiled members such as alias of basic types
18     enum hasSpecificUDA(string name) = mixin("hasUDA!(symbol." ~ name ~ ", attribute)");
19     enum noIncorrectMembers(string name) = (__traits(compiles, hasSpecificUDA!(name)));
20 
21     alias withoutIncorrectMembers = Filter!(noIncorrectMembers, membersWithoutNestedCC);
22     alias membersWithUDA = Filter!(hasSpecificUDA, withoutIncorrectMembers);
23 
24     // if the symbol itself has the UDA, tack it on to the front of the list
25     static if (hasUDA!(symbol, attribute))
26         alias getSymbolsNamesByUDA = AliasSeq!(symbol, membersWithUDA);
27     else
28         alias getSymbolsNamesByUDA = membersWithUDA;
29 }
30 
31 template getSymbolsByUDA(alias symbol, alias attribute) {
32     import std.format : format;
33     import std.meta : AliasSeq, Filter;
34 
35     // translate a list of strings into symbols. mixing in the entire alias
36     // avoids trying to access the symbol, which could cause a privacy violation
37     template toSymbols(names...) {
38         static if (names.length == 0)
39             alias toSymbols = AliasSeq!();
40         else
41             mixin("alias toSymbols = AliasSeq!(symbol.%s, toSymbols!(names[1..$]));"
42                   .format(names[0]));
43     }
44 
45     // filtering inaccessible members
46     enum isAccessibleMember(string name) = __traits(compiles, __traits(getMember, symbol, name));
47     alias accessibleMembers = Filter!(isAccessibleMember, __traits(allMembers, symbol));
48 
49     // filtering not compiled members such as alias of basic types
50     enum hasSpecificUDA(string name) = mixin("hasUDA!(symbol." ~ name ~ ", attribute)");
51     enum isCorrectMember(string name) = __traits(compiles, hasSpecificUDA!(name));
52 
53     alias correctMembers = Filter!(isCorrectMember, accessibleMembers);
54     alias membersWithUDA = toSymbols!(Filter!(hasSpecificUDA, correctMembers));
55 
56     // if the symbol itself has the UDA, tack it on to the front of the list
57     static if (hasUDA!(symbol, attribute))
58         alias getSymbolsByUDA = AliasSeq!(symbol, membersWithUDA);
59     else
60         alias getSymbolsByUDA = membersWithUDA;
61 }