1 /**
2    Helper functions for dealing with UDAs, written before hasUDA and
3    others were added to Phobos.
4  */
5 module unit_threaded.uda;
6 
7 private template Identity(T...) if(T.length > 0) {
8     static if(__traits(compiles, { alias x = T[0]; }))
9         alias Identity = T[0];
10     else
11         enum Identity = T[0];
12 }
13 
14 
15 /**
16  * For the given module, return true if this module's member has
17  * the given UDA. UDAs can be types or values.
18  */
19 template HasAttribute(alias module_, string moduleMember, alias attribute) {
20     import unit_threaded.meta: importMember;
21     import std.meta: Filter;
22 
23     alias member = Identity!(__traits(getMember, module_, moduleMember));
24 
25     static if(!__traits(compiles, __traits(getAttributes, member)))
26         enum HasAttribute = false;
27     else {
28         enum isAttribute(alias T) = is(TypeOf!T == attribute);
29         alias attrs = Filter!(isAttribute, __traits(getAttributes, member));
30 
31         static assert(attrs.length == 0 || attrs.length == 1,
32                       text("Maximum number of attributes is 1 for ", attribute));
33 
34         static if(attrs.length == 0) {
35             enum HasAttribute = false;
36         } else {
37             enum HasAttribute = true;
38         }
39     }
40 }
41 
42 /**
43  * For the given module, return true if this module's member has
44  * the given UDA. UDAs can be types or values.
45  */
46 template GetAttributes(alias module_, string member, A) {
47     import unit_threaded.meta: importMember;
48     import std.meta: Filter;
49 
50     mixin(importMember!module_(member));
51     enum isAttribute(alias T) = is(TypeOf!T == A);
52     alias GetAttributes = Filter!(isAttribute, __traits(getAttributes, mixin(member)));
53 }
54 
55 
56 /**
57  * Utility to allow checking UDAs regardless of whether the template
58  * parameter is or has a type
59  */
60 private template TypeOf(alias T) {
61     static if(__traits(compiles, typeof(T))) {
62         alias TypeOf = typeof(T);
63     } else {
64         alias TypeOf = T;
65     }
66 }
67 
68 
69 template isTypesAttr(alias T) {
70     import unit_threaded.attrs;
71     enum isTypesAttr = is(T) && is(T:Types!U, U...);
72 }
73 
74 
75 /*
76  @Types is different from the other UDAs since it's a templated struct
77  None of the templates above work so we special case it here
78 */
79 
80 /// If a test has the @Types UDA
81 enum HasTypes(alias T) = GetTypes!T.length > 0;
82 
83 /// Returns the types in the @Types UDA associated to a test
84 template GetTypes(alias T) {
85     import std.meta: Filter, AliasSeq;
86     import std.traits: TemplateArgsOf;
87 
88     static if(!__traits(compiles, __traits(getAttributes, T))) {
89         alias GetTypes = AliasSeq!();
90     } else {
91         alias types = Filter!(isTypesAttr, __traits(getAttributes, T));
92         static if(types.length > 0)
93             alias GetTypes = TemplateArgsOf!(types[0]);
94         else
95             alias GetTypes = AliasSeq!();
96     }
97 }
98 
99 
100 
101 // copy of recent hasUDA from Phobos here because old
102 // compilers will fail otherwise
103 
104 enum hasUtUDA(alias symbol, alias attribute) = getUtUDAs!(symbol, attribute).length > 0;
105 
106 template getUtUDAs(alias symbol, alias attribute)
107 {
108     import std.meta : Filter;
109     import std.traits: isInstanceOf;
110 
111     template isDesiredUDA(alias toCheck)
112     {
113         static if (is(typeof(attribute)) && !__traits(isTemplate, attribute))
114         {
115             static if (__traits(compiles, toCheck == attribute))
116                 enum isDesiredUDA = toCheck == attribute;
117             else
118                 enum isDesiredUDA = false;
119         }
120         else static if (is(typeof(toCheck)))
121         {
122             static if (__traits(isTemplate, attribute))
123                 enum isDesiredUDA =  isInstanceOf!(attribute, typeof(toCheck));
124             else
125                 enum isDesiredUDA = is(typeof(toCheck) == attribute);
126         }
127         else static if (__traits(isTemplate, attribute))
128             enum isDesiredUDA = isInstanceOf!(attribute, toCheck);
129         else
130             enum isDesiredUDA = is(toCheck == attribute);
131     }
132 
133     alias getUtUDAs = Filter!(isDesiredUDA, __traits(getAttributes, symbol));
134 }