1 /** 2 Helper functions for dealing with UDAs, written before hasUDA and 3 others were added to Phobos. 4 */ 5 module unit_threaded.runner.traits; 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.runner.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.runner.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.runner.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 }