1 /** 2 Provides compile time utilities that can query a type's members 3 */ 4 module bolts.members; 5 6 import bolts.internal; 7 8 private template AliasesOf(T, membersTuple...) { 9 import std.meta: Alias, staticMap, ApplyLeft; 10 alias getMember(T, string name) = Alias!(__traits(getMember, T, name)); 11 alias mapMembers(T, names...) = staticMap!(ApplyLeft!(getMember, T), names); 12 alias AliasesOf = mapMembers!(T, membersTuple); 13 } 14 15 /** 16 Returns a list of member functions of T 17 18 You can retireve them as a tuple of aliases, or strings 19 */ 20 template memberFunctionsOf(T) { 21 import bolts.traits: hasFunctionMember; 22 import bolts.meta: FilterMembersOf; 23 24 /// Get as tuple of strings 25 alias asStrings = FilterMembersOf!(T, hasFunctionMember); 26 27 /// Get as a tuple of aliases 28 alias asAliases = AliasesOf!(T, memberFunctionsOf!T.asStrings); 29 } 30 31 /// 32 unittest { 33 import std.meta: AliasSeq; 34 struct A { 35 void opCall() {} 36 void g() {} 37 } 38 39 struct B { 40 int m; 41 A a; 42 alias a this; 43 void f0() {} 44 void f1() {} 45 } 46 47 immutable array = [memberFunctionsOf!B.asStrings]; 48 alias strings = memberFunctionsOf!B.asStrings; 49 alias aliases = memberFunctionsOf!B.asAliases; 50 51 static assert(array == ["f0", "f1"]); 52 static assert(strings == AliasSeq!("f0", "f1")); 53 54 static assert(is(typeof(array) == immutable string[])); 55 static assert(is(typeof(strings) == AliasSeq!(string, string))); 56 static assert(is(typeof(aliases) == AliasSeq!(typeof(B.f0), typeof(B.f1)))); 57 } 58 59 /** 60 Returns a list of all the static members of a type 61 62 You can retireve them as a sequence of aliases, or strings. 63 64 See_Also: 65 - https://forum.dlang.org/post/duvxnpwnuphuxlrkjplh@forum.dlang.org 66 */ 67 template staticMembersOf(T) { 68 import std.traits: hasStaticMember; 69 import bolts.meta: FilterMembersOf; 70 71 /// Get as tuple of strings 72 alias asStrings = FilterMembersOf!(T, hasStaticMember); 73 74 /// Get as a tuple of aliases 75 alias asAliases = AliasesOf!(T, staticMembersOf!T.asStrings); 76 } 77 78 /// 79 unittest { 80 import std.meta: AliasSeq, Alias; 81 import bolts.traits: TypesOf; 82 struct S { 83 static void s0() {} 84 static int s1 = 3; 85 static immutable int s2 = 3; 86 enum e = 9; 87 void f() {} 88 int i = 3; 89 } 90 91 immutable array = [staticMembersOf!S.asStrings]; 92 alias strings = staticMembersOf!S.asStrings; 93 alias aliases = staticMembersOf!S.asAliases; 94 95 static assert(array == ["s0", "s1", "s2"]); 96 static assert(strings == AliasSeq!("s0", "s1", "s2")); 97 98 static assert(is(typeof(array) == immutable string[])); 99 static assert(is(typeof(strings) == AliasSeq!(string, string, string))); 100 static assert(is(typeof(aliases) == AliasSeq!(typeof(S.s0), typeof(S.s1), typeof(S.s2)))); 101 } 102 103 /** 104 Used to extract details about a specific member 105 106 Available member traits: 107 $(LI `exists`) 108 $(LI `self`) 109 $(LI `isProperty`) 110 $(LI `protection`) 111 112 Params: 113 Params[0] = type or alias to instance of a type 114 Params[1] = name of member 115 116 */ 117 template member(Params...) if (Params.length == 2) { 118 private enum name = Params[1]; 119 private alias T = bolts.traits.TypesOf!Params[0]; 120 private alias ResolvedType = ResolvePointer!T; 121 122 /** 123 True if the member field exists 124 */ 125 enum exists = __traits(hasMember, ResolvedType, name); 126 127 /** 128 Aliases to the member if it exists 129 */ 130 static if (exists) { 131 alias self = __traits(getMember, ResolvedType, name); 132 } else { 133 template self() { 134 static assert( 135 0, 136 "Type '" ~ T.stringof ~ "' does not have member '" ~ name ~ "'." 137 ); 138 } 139 } 140 141 /** 142 See: `bolts.traits.protectionLevel` 143 */ 144 static if (exists) { 145 enum protection = from.bolts.traits.protectionLevel!self; 146 } 147 148 /** 149 See: `bolts.traits.hasProperty` 150 */ 151 static if (exists) { 152 enum isProperty = from.bolts.traits.hasProperty!(ResolvedType, name); 153 } else { 154 enum isProperty = false; 155 } 156 157 /** 158 See `bolts.traits.propertySemantics` 159 */ 160 static if (exists && isProperty) { 161 enum propertySemantics = from.bolts.traits.propertySemantics!self; 162 } 163 } 164 165 /// 166 unittest { 167 import bolts.traits: ProtectionLevel, PropertySemantics; 168 static struct S { 169 public int publicI; 170 protected int protectedI; 171 private @property int readPropI() { return protectedI; } 172 } 173 174 // Check the protection level of various members 175 static assert(member!(S, "publicI").protection == ProtectionLevel.public_); 176 static assert(member!(S, "protectedI").protection == ProtectionLevel.protected_); 177 static assert(member!(S, "readPropI").protection == ProtectionLevel.private_); 178 179 // Check if any are properties 180 static assert(!member!(S, "na").isProperty); 181 static assert(!member!(S, "publicI").isProperty); 182 static assert( member!(S, "readPropI").isProperty); 183 184 // Check their semantics 185 static assert(member!(S, "readPropI").propertySemantics == PropertySemantics.r); 186 }