1 /**
2  * Copyright: Copyright (c) 2009-2011 Jacob Carlborg.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Oct 5, 2009
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module orange.util.Reflection;
8 
9 import orange.util.CTFE;
10 
11 /**
12  * Evaluates to true if T has a field with the given name
13  *
14  * Params:
15  *         T = the type of the class/struct
16  *         field = the name of the field
17  */
18 template hasField (T, string field)
19 {
20     enum hasField = hasFieldImpl!(T, field, 0);
21 }
22 
23 private template hasFieldImpl (T, string field, size_t i)
24 {
25     static if (T.tupleof.length == i)
26         enum hasFieldImpl = false;
27 
28     else static if (nameOfFieldAt!(T, i) == field)
29         enum hasFieldImpl = true;
30 
31     else
32         enum hasFieldImpl = hasFieldImpl!(T, field, i + 1);
33 }
34 
35 /**
36  * Evaluates to an array of strings containing the names of the fields in the given type
37  */
38 template fieldsOf (T)
39 {
40     enum fieldsOf = fieldsOfImpl!(T, 0);
41 }
42 
43 /**
44  * Implementation for fieldsOf
45  *
46  * Returns: an array of strings containing the names of the fields in the given type
47  */
48 template fieldsOfImpl (T, size_t i)
49 {
50     static if (T.tupleof.length == 0)
51         enum fieldsOfImpl = [""];
52 
53     else static if (T.tupleof.length - 1 == i)
54         enum fieldsOfImpl = [nameOfFieldAt!(T, i)];
55 
56     else
57         enum fieldsOfImpl = nameOfFieldAt!(T, i) ~ fieldsOfImpl!(T, i + 1);
58 }
59 
60 /**
61  * Evaluates to the type of the field with the given name
62  *
63  * Params:
64  *         T = the type of the class/struct
65  *         field = the name of the field
66  */
67 template TypeOfField (T, string field)
68 {
69     static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
70 
71     alias TypeOfFieldImpl!(T, field, 0) TypeOfField;
72 }
73 
74 private template TypeOfFieldImpl (T, string field, size_t i)
75 {
76     static if (nameOfFieldAt!(T, i) == field)
77         alias typeof(T.tupleof[i]) TypeOfFieldImpl;
78 
79     else
80         alias TypeOfFieldImpl!(T, field, i + 1) TypeOfFieldImpl;
81 }
82 
83 /**
84  * Evaluates to a string containing the name of the field at given position in the given type.
85  *
86  * Params:
87  *         T = the type of the class/struct
88  *         position = the position of the field in the tupleof array
89  */
90 template nameOfFieldAt (T, size_t position)
91 {
92     static assert (position < T.tupleof.length, format!(`The given position "`, position, `" is greater than the number of fields (`, T.tupleof.length, `) in the type "`, T, `"`));
93 
94     enum nameOfFieldAt = __traits(identifier, T.tupleof[position]);
95 }
96 
97 /**
98  * Sets the given value to the filed with the given name
99  *
100  * Params:
101  *     t = an instance of the type that has the field
102  *     value = the value to set
103  */
104 void setValueOfField (T, U, string field) (ref T t, U value)
105 in
106 {
107     static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
108 }
109 body
110 {
111     enum len = T.stringof.length;
112 
113     foreach (i, dummy ; typeof(T.tupleof))
114     {
115         static if (nameOfFieldAt!(T, i) == field)
116         {
117             t.tupleof[i] = value;
118             break;
119         }
120     }
121 }
122 
123 /**
124  * Gets the value of the field with the given name
125  *
126  * Params:
127  *     t = an instance of the type that has the field
128  *
129  * Returns: the value of the field
130  */
131 U getValueOfField (T, U, string field) (T t)
132 in
133 {
134     static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
135 }
136 body
137 {
138     enum len = T.stringof.length;
139 
140     foreach (i, dummy ; typeof(T.tupleof))
141     {
142         static if (nameOfFieldAt!(T, i) == field)
143             return t.tupleof[i];
144     }
145 
146     assert(0);
147 }
148 
149 private
150 {
151     version (LDC)
152         extern (C) Object _d_allocclass(in ClassInfo);
153 
154     else
155         extern (C) Object _d_newclass(in ClassInfo);
156 }
157 
158 /**
159  * Returns a new instnace of the class associated with the given class info.
160  *
161  * Params:
162  *     classInfo = the class info associated with the class
163  *
164  * Returns: a new instnace of the class associated with the given class info.
165  */
166 Object newInstance (in ClassInfo classInfo)
167 {
168     version (LDC)
169     {
170         Object object = _d_allocclass(classInfo);
171         const(void)[]defInitializer = classInfo.initializer();
172         if ((defInitializer !is null) && (defInitializer.length > 0)) {
173             if (defInitializer.ptr !is null)
174                 (cast(byte*) object)[0..defInitializer.length] = (cast(byte*)defInitializer.ptr)[0..defInitializer.length];
175             else
176                 (cast(byte*) object)[0..defInitializer.length] = 0;
177         }
178         return object;
179     }
180 
181     else
182         return _d_newclass(classInfo);
183 }
184 
185 /**
186  * Return a new instance of the class with the given name.
187  *
188  * Params:
189  *     name = the fully qualified name of the class
190  *
191  * Returns: a new instance or null if the class name could not be found
192  */
193 Object newInstance (string name)
194 {
195     auto classInfo = ClassInfo.find(name);
196 
197     if (!classInfo)
198         return null;
199 
200     return newInstance(classInfo);
201 }