1 /// Original Phobos drop-in replacement traits, superseded by the new Tern traits system. 2 module tern.legacy.traits; 3 4 public import std.traits : fullyQualifiedName, mangledName, moduleName, packageName, 5 isFunction, arity, functionAttributes, hasFunctionAttributes, functionLinkage, FunctionTypeOf, isSafe, isUnsafe, 6 isFinal, ParameterDefaults, SetFunctionAttributes, FunctionAttribute, variadicFunctionStyle, EnumMembers, 7 hasAliasing, hasElaborateAssign, hasElaborateCopyConstructor, hasElaborateDestructor, hasElaborateMove, hasIndirections, 8 hasMember, hasStaticMember, hasNested, hasUnsharedAliasing, isInnerClass, isNested, TemplateArgsOf, TemplateOf, 9 CommonType, AllImplicitConversionTargets, ImplicitConversionTargets, CopyTypeQualifiers, CopyConstness, isAssignable, 10 isCovariantWith, isImplicitlyConvertible, isQualifierConvertible, InoutOf, ConstOf, SharedOf, SharedInoutOf, SharedConstOf, 11 SharedConstInoutOf, ImmutableOf, QualifierOf, allSameType, isType, isAggregateType, isArray, isAssociativeArray, isAutodecodableString, 12 isBasicType, isBoolean, isBuiltinType, isCopyable, isDynamicArray, isEqualityComparable, isFloatingPoint, isIntegral, isNarrowString, 13 isConvertibleToString, isNumeric, isOrderingComparable, isPointer, isScalarType, isSigned, isSIMDVector, isSomeChar, isSomeString, 14 isStaticArray, isUnsigned, isAbstractClass, isAbstractFunction, isDelegate, isExpressions, isFinalClass, isFinalFunction, isFunctionPointer, 15 isInstanceOf, isSomeFunction, isTypeTuple, Unconst, Unshared, Unqual, Signed, Unsigned, ValueType, Promoted, Select, select, 16 hasUDA, getUDAs, getSymbolsByUDA; 17 import std.traits; 18 import std.meta; 19 import std.string; 20 21 /// Gets an alias to the package in which `A` is defined, undefined behavior for any alias that does not have a package (any intrinsic type.) 22 public alias getPackage(alias A) = mixin(fullyQualifiedName!A.indexOf(".") == -1 ? fullyQualifiedName!A : fullyQualifiedName!A[0..fullyQualifiedName!A.indexOf(".")]); 23 /// True if `T` is an indirection. 24 public enum isReferenceType(T) = is(T == class) || is(T == interface) || isPointer!T || isDynamicArray!T || isAssociativeArray!T; 25 /// True if `T` is not an indirection. 26 public enum isValueType(T) = is(T == struct) || is(T == enum) || is(T == union) || isBuiltinType!T || hasModifiers!T; 27 /// True if `A` is a template. 28 public enum isTemplate(alias A) = __traits(isTemplate, A); 29 /// True if `A` is a module. 30 public enum isModule(alias A) = __traits(isModule, A); 31 /// True if `A` is a package. 32 public enum isPackage(alias A) = __traits(isPackage, A); 33 /// True if `A` is a field. 34 public enum isField(alias A) = !isType!A && !isFunction!A && !isTemplate!A && !isModule!A && !isPackage!A; 35 /// True if `A` is a local. 36 public enum isLocal(alias A) = !isManifest!A && !__traits(compiles, { enum _ = A; }) && __traits(compiles, { auto _ = A; }); 37 /// True if `T` is a basic type, built-in type, or array. 38 public enum isBuiltinType(T) = isBasicType!T || isBuiltinType!T || isArray!T; 39 /// True if `A` has any parents. 40 public enum hasParents(alias A) = (!isType!A || !isBuiltinType!A) && !isPackage!A; 41 /// True if `T` is an enum, array, or pointer. 42 public enum hasModifiers(T) = isArray!T || isPointer!T || !isAggregateType!T; 43 /// True if `A` has any children. 44 public enum hasChildren(alias A) = isModule!A || isPackage!A || (!isType!A || (!isBuiltinType!A && !hasModifiers!A)); 45 /// True if `T` has any instance constructor ("__ctor"). 46 public enum hasConstructor(alias A) = hasMember!(T, "__ctor"); 47 /// True if `F` is a constructor; 48 public enum isConstructor(alias F) = isFunction!F && (__traits(identifier, F).startsWith("__ctor") || __traits(identifier, F).startsWith("_staticCtor")); 49 /// True if `F` is a destructor. 50 public enum isDestructor(alias F) = isFunction!F && (__traits(identifier, F).startsWith("__dtor") || __traits(identifier, F).startsWith("__xdtor") || __traits(identifier, F).startsWith("_staticDtor")); 51 /// True if `A` is a static field. 52 public enum isStatic(alias A) = !isManifest!A && ((isField!A && __traits(compiles, { auto _ = __traits(getMember, __traits(parent, A), __traits(identifier, A)); })) || (isLocal!A && __traits(compiles, { static auto _() { return A; } }))); 53 /// True if `A` is an enum field or local. 54 public enum isManifest(alias A) = __traits(compiles, { enum _ = __traits(getMember, __traits(parent, A), __traits(identifier, A)); }); 55 /// True if `A` is an implementation defined alias (ie: __ctor, std, rt, etc.) 56 public enum isDImplDefined(alias A) = 57 { 58 static if ((isModule!A || (isType!A && !isBuiltinType!A)) && (getPackage!A.stringof == "package std" || getPackage!A.stringof == "package rt" || getPackage!A.stringof == "package core")) 59 return true; 60 else static if (isPackage!A && (A.stringof == "package std" || A.stringof == "package rt" || A.stringof == "package core")) 61 return true; 62 else static if (isType!A && isBuiltinType!A) 63 return true; 64 else static if (isFunction!A && 65 // Not exactly accurate but good enough 66 (__traits(identifier, A).startsWith("_d_") || __traits(identifier, A).startsWith("rt_") || 67 __traits(identifier, A).startsWith("__") || __traits(identifier, A).startsWith("op"))) 68 return true; 69 else static if (isConstructor!A || isDestructor!A || (isFunction!F && (__traits(identifier, F).startsWith("toHash") || __traits(identifier, F).startsWith("toString")))) 70 return true; 71 else 72 return false; 73 }(); 74 /// True if `A` is not D implementation defined. 75 public enum isOrganic(alias A) = !isDImplDefined!A; 76 /// True if `A` is able to be indexed. 77 public enum isIndexable(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; auto _ = t[0]; }); 78 /// True if `A` is able to be iterated upon forwards. 79 public enum isForward(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; foreach (u; t) { } }); 80 /// True if `A` is able to be iterated upon forwards. 81 public enum isBackward(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; foreach_reverse (u; t) { } }); 82 /// True if `B` is an element type of `A` (assignable as element.) 83 public enum isElement(A, B) = isAssignable!(B, ElementType!A); 84 /// True if `B` is able to be used as a range the same as `A`. 85 public enum isSimRange(A, B) = isAssignable!(ElementType!B, ElementType!A); 86 /// True if `F` is a lambda. 87 public enum isLambda(alias F) = __traits(identifier, F).startsWith("__lambda"); 88 /// True if `F` is a dynamic lambda (templated, ie: `x => x + 1`) 89 public enum isTemplatedCallable(alias F) = std.traits.isCallable!(DefaultInstance!F); 90 /// True if `F` is a dynamic lambda (templated, ie: `x => x + 1`) 91 public enum isDynamicLambda(alias F) = isLambda!F && is(typeof(F) == void); 92 /// True if `F` is a function, lambda, or otherwise may be called using `(...)` 93 public enum isCallable(alias F) = std.traits.isCallable!F || isLambda!F || isTemplatedCallable!F; 94 /// True if `F` is a property of any kind. 95 public enum isProperty(alias F) = hasUDA!(F, property); 96 /// True if `F` is a pure callable. 97 public enum isPure(alias F) = isCallable!F && hasFunctionAttributes!(F, "pure"); 98 /// True if `B` implements `A`. 99 public enum isImplement(A, B) = staticIndexOf!(A, Implements!B) != -1; 100 /// True if `A` is not mutable (const, immutable, enum, etc.). 101 public enum isMutable(alias A) = 102 { 103 static if (isType!A) 104 return std.traits.isMutable!A; 105 else static if (isField!A) 106 return std.traits.isMutable!(typeof(A)) || !isManifest!A; 107 else 108 return false; 109 }(); 110 111 /// Gets the alignment of `T` dynamically, returning the actual instance alignment. 112 public enum alignof(T) = 113 { 114 static if (is(T == class)) 115 return __traits(classInstanceAlignment, T); 116 else 117 return T.alignof; 118 }(); 119 120 /// Gets the size of `T` dynamically, returning the actual instance size. 121 public enum sizeof(T) = 122 { 123 static if (is(T == class)) 124 return __traits(classInstanceSize, T); 125 else 126 return T.sizeof; 127 }(); 128 129 /// Gets the type of member `MEMBER` in `A` 130 /// This will return a function alias if `MEMBER` refers to a function, and do god knows what if `MEMBER` is a package or module. 131 public template TypeOf(alias A, string MEMBER) 132 { 133 static if (isType!(__traits(getMember, A, MEMBER)) || isTemplate!(__traits(getMember, A, MEMBER)) || isFunction!(__traits(getMember, A, MEMBER))) 134 alias TypeOf = __traits(getMember, A, MEMBER); 135 else 136 alias TypeOf = typeof(__traits(getMember, A, MEMBER)); 137 } 138 139 /// Gets the return type of a callable symbol. 140 public template ReturnType(alias F) 141 if (isCallable!F) 142 { 143 static if (isLambda!F && !__traits(compiles, { alias _ = std.traits.ReturnType!F; })) 144 { 145 typeof(toDelegate(F)) dg; 146 alias ReturnType = TypeOf!dg; 147 } 148 else 149 alias ReturnType = std.traits.ReturnType!F; 150 } 151 152 /// Gets the parameters of a callable symbol. 153 public template Parameters(alias F) 154 if (isCallable!F) 155 { 156 static if (isLambda!F && !__traits(compiles, { alias _ = std.traits.Parameters!F; })) 157 { 158 typeof(toDelegate(F)) dg; 159 alias Parameters = std.traits.Parameters!dg; 160 } 161 else 162 alias Parameters = std.traits.Parameters!F; 163 } 164 165 /// Gets the element type of `T`, if applicable. 166 /// Returns the type of enum values if `T` is an enum. 167 public template ElementType(T) 168 { 169 static if (is(T == U[], U) || is(T == U*, U) || is(T U == U[L], size_t L)) 170 alias ElementType = ElementType!U; 171 else static if (isIndexable!T) 172 { 173 T temp; 174 alias ElementType = ElementType!(typeof(temp[0])); 175 } 176 else 177 alias ElementType = OriginalType!T; 178 } 179 180 /// Gets the length of `T`, if applicable. 181 public template Length(T) 182 { 183 static if (is(T U == U[L], size_t L)) 184 enum Length = L; 185 } 186 187 /// Gets an `AliasSeq` all types that `T` implements. 188 public template Implements(T) 189 { 190 template Flatten(H, T...) 191 { 192 static if (T.length) 193 { 194 alias Flatten = AliasSeq!(Flatten!H, Flatten!T); 195 } 196 else 197 { 198 static if (!is(H == Object) && (is(H == class) || is(H == interface))) 199 alias Flatten = AliasSeq!(H, Implements!H); 200 else 201 alias Flatten = Implements!H; 202 } 203 } 204 205 static if (is(T S == super) && S.length) 206 { 207 static if (__traits(getAliasThis, T).length != 0) 208 alias Implements = AliasSeq!(TypeOf!(T, __traits(getAliasThis, T)), Implements!(TypeOf!(T, __traits(getAliasThis, T))), NoDuplicates!(Flatten!S)); 209 else 210 alias Implements = NoDuplicates!(Flatten!S); 211 } 212 else 213 { 214 static if (__traits(getAliasThis, T).length != 0) 215 alias Implements = AliasSeq!(TypeOf!(T, __traits(getAliasThis, T)), Implements!(TypeOf!(T, __traits(getAliasThis, T)))); 216 else 217 alias Implements = AliasSeq!(); 218 } 219 } 220 221 /// Gets an `AliasSeq` of the names of all fields in `A`. 222 public template Fields(alias A) 223 { 224 alias Fields = AliasSeq!(); 225 226 static if (hasChildren!A) 227 static foreach (member; __traits(allMembers, A)) 228 { 229 static if (isField!(__traits(getMember, A, member))) 230 Fields = AliasSeq!(Fields, member); 231 } 232 } 233 234 /// Gets an `AliasSeq` of the names all functions in `A`. 235 public template Functions(alias A) 236 { 237 alias Functions = AliasSeq!(); 238 239 static if (hasChildren!A) 240 static foreach (member; __traits(allMembers, A)) 241 { 242 static if (isFunction!(__traits(getMember, A, member))) 243 Functions = AliasSeq!(Functions, member); 244 } 245 } 246 247 /// Gets an `AliasSeq` of the names of all types in `A`. 248 public template Types(alias A) 249 { 250 alias Types = AliasSeq!(); 251 252 static if (hasChildren!A) 253 static foreach (member; __traits(allMembers, A)) 254 { 255 static if (isType!(__traits(getMember, A, member))) 256 Types = AliasSeq!(Types, member); 257 } 258 } 259 260 /// Gets an `AliasSeq` of the names of all templates in `A`. 261 public template Templates(alias A) 262 { 263 alias Templates = AliasSeq!(); 264 265 static if (hasChildren!A) 266 static foreach (member; __traits(allMembers, A)) 267 { 268 static if (isTemplate!(__traits(getMember, A, member))) 269 Templates = AliasSeq!(Templates, member); 270 } 271 }