root/trunk/src/semitwist/util/reflect.d

Revision 240, 4.8 kB (checked in by Abscissa, 6 months ago)

Fixed for 64bit

  • Property svn:eol-style set to native
Line 
1 // SemiTwist Library
2 // Written in the D programming language.
3
4 module semitwist.util.reflect;
5
6 import std.conv;
7 import std.demangle;
8 import std.functional;
9 import std.traits;
10 import std.typetuple;
11
12 import semitwist.util.all;
13
14 /++
15 If you have a class MyClass(T), then nameof!(MyClass) will return "MyClass".
16
17 One benefit of this is that you can do things like:
18     mixin("auto obj = new "~nameof!(MyClass)~"!(int)()");
19 or
20     throw new Exception("Something's wrong with a "~nameof!(MyClass)~" object!";
21 and the "MyClass" will be checked by the compiler, alerting you immediately
22 if the class name changes, helping you keep such strings up-to-date.
23 +/
24 template nameof(alias T)
25 {
26     enum string nameof = T.stringof[0..ctfe_find(to!(char[])(T.stringof), '(')];
27 }
28
29 template isAnyArray(T)
30 {
31     enum bool isAnyArray =
32         isArray!(T) ||
33         isAssociativeArray!(T);
34 }
35
36 /// If T isn't an array, returns T[], otherwise returns T as-is.
37 template EnsureArray(T)
38 {
39     static if(isArray!(T))
40         alias T EnsureArray;
41     else
42         alias T[] EnsureArray;
43 }
44
45 template callableExists(T)
46 {
47     static if(is(T) && isCallable(typeof(T)))
48         enum bool callableExists = true;
49     else
50         enum bool callableExists = false;
51 }
52
53 template ExprTypeOf(T)
54 {
55     static if(isCallable!(T))
56         alias ReturnType!(T) ExprTypeOf;
57     else
58         alias T ExprTypeOf;
59 }
60
61 string qualifiedName(alias ident)()
62 {
63     string mangled = mangledName!ident;
64    
65     // Work around DMD Issue #5718: Can't demangle symbol defined inside unittest block
66     auto startIndex = ctfe_find(mangled, "_D");
67     if(startIndex == mangled.length)
68         startIndex = 0;
69    
70     return demangle(mangled[startIndex..$]);
71 }
72
73 /// Checks if value 'a' is, or is implicitly castable to, or is derived from type T.
74 template isType(T)
75 {
76     bool isType(Ta)(Ta a)
77     {
78         static if(is(Ta : T))
79             return true;
80
81         else static if(!is(Ta : Object) || !is(T : Object))
82             return false;
83
84         else static if(!__traits(compiles, cast(T)a))
85             return false;
86
87         else
88             return cast(T)a !is null;
89     }
90 }
91
92 mixin(unittestSemiTwistDLib("isType", q{
93
94     class Foo {}
95     class Bar {}
96     auto f = new Foo();
97
98     mixin(deferAssert!(q{ isType!int(3)     }));
99     mixin(deferAssert!(q{ isType!double(3)  }));
100     mixin(deferAssert!(q{ !isType!string(3) }));
101     mixin(deferAssert!(q{ !isType!Foo(3)    }));
102    
103     mixin(deferAssert!(q{ isType!Foo(f)               }));
104     mixin(deferAssert!(q{ isType!Object(f)            }));
105     mixin(deferAssert!(q{ isType!Foo( cast(Object)f ) }));
106     mixin(deferAssert!(q{ !isType!Bar(f)              }));
107     mixin(deferAssert!(q{ !isType!int(f)              }));
108
109 }));
110
111 /// Checks if value 'a' is, or is implicitly castable to, or is derived from any of the TList types.
112 /// Example: assert( isAnyType!(Foo, Bar, Baz)(foo) );
113 template isAnyType(TList...)
114 {
115     bool isAnyType(T)(T val)
116     {
117         foreach(TTest; TList)
118         if(isType!TTest(val))
119             return true;
120        
121         return false;
122     }
123 }
124
125 /// Checks if value 'a' is, or is implicitly castable to, or is derived from all of the TList types.
126 /// Example: assert( isAllTypes!(Foo, Bar, Baz)(foo) );
127 template isAllTypes(TList...)
128 {
129     bool isAllTypes(T)(T val)
130     {
131         foreach(TTest; TList)
132         if(!isType!TTest(val))
133             return false;
134        
135         return true;
136     }
137 }
138
139 mixin(unittestSemiTwistDLib("isAnyType / isAllTypes", q{
140
141     class Foo {}
142     class Bar {}
143     auto f = new Foo();
144
145     mixin(deferAssert!(q{  isAnyType !(int, double)(3) }));
146     mixin(deferAssert!(q{  isAllTypes!(int, double)(3) }));
147     mixin(deferAssert!(q{  isAnyType !(int, Foo)(3)    }));
148     mixin(deferAssert!(q{ !isAllTypes!(int, Foo)(3)    }));
149     mixin(deferAssert!(q{ !isAnyType !(Foo, Object)(3) }));
150
151     mixin(deferAssert!(q{  isAnyType !(Foo, Object)(f) }));
152     mixin(deferAssert!(q{  isAllTypes!(Foo, Object)(f) }));
153     mixin(deferAssert!(q{  isAnyType !(int, Foo)(f)    }));
154     mixin(deferAssert!(q{ !isAllTypes!(int, Foo)(f)    }));
155     mixin(deferAssert!(q{  isAnyType !(Bar, Foo)(f)    }));
156     mixin(deferAssert!(q{ !isAllTypes!(Bar, Foo)(f)    }));
157     mixin(deferAssert!(q{ !isAnyType !(int, Bar)(f)    }));
158
159 }));
160
161 /++
162 Calls .stringof on each argument then returns
163 the results in an array of strings.
164
165 (NOTE: Not actually intended as a mixin itself.)
166
167 Example:
168
169 ----
170 int i;
171 void func1(){}
172 // void func2(int x){} // This one doesn't work ATM due to DMD Bug #2867
173
174 immutable string[] foo = templateArgsToStrings!(i, func1);
175 assert(foo == ["i"[], "func1"]);
176 ----
177
178 +/
179 /+template templateArgsToStrings(args...)
180 {
181     static if(args.length == 0)
182         immutable string[] templateArgsToStrings = [];
183     else
184         immutable string[] templateArgsToStrings =
185             (   // Ugly hack for DMD Bug #2867
186                 (args[0].stringof.length>2 && args[0].stringof[$-2..$]=="()")?
187                     args[0].stringof[0..$-2] :
188                     args[0].stringof[]
189             )
190             ~ templateArgsToStrings!(args[1..$]);
191 }
192
193 unittest
194 {
195     int i;
196     void func1(){}
197     //void func2(int x){} // This one doesn't work ATM due to DMD Bug #2867
198
199     immutable string[] templateArgsToStrings_test = templateArgsToStrings!(i, func1);
200     mixin(deferEnsure!(`templateArgsToStrings_test`, `_ == ["i", "func1"]`));
201 }+/
Note: See TracBrowser for help on using the browser.