1 /*
2 Copyright (c) 2013 Andrey Penechko
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license the "Software" to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 // Provides optimized ways to interact with FlexibleObject descendants properties, which have some
30 // built in properties.
31 //
32 // If property name is statically specified and there is built in property with that name then it will be bound to it without looking into property array,
33 // otherwise it will look into property array. This will speed up binding of properties which is accessible at compile time.
34 module anchovy.utils.flexibleobject.flexibleaccess;
35 
36 import std.traits : hasMember;
37 import std.variant : Variant;
38 import anchovy.utils.flexibleobject.flexibleobject : FlexibleObject;
39 
40 
41 private template hasStaticProperty(T, string property)
42 {
43 	enum hasStaticProperty = __traits(hasMember, T, property);
44 }
45 
46 // ditto
47 static Variant getProperty(string propname, FlexibleObjectType : FlexibleObject)(FlexibleObjectType w)
48 {
49 	static if(hasStaticProperty!(FlexibleObjectType, propname))
50 	{
51 		return mixin("w."~propname);
52 	}
53 	else
54 	{
55 		return w[propname];
56 	}
57 }
58 
59 //
60 //
61 //
62 static T getPropertyAs(T)(string propname, FlexibleObject w)
63 {
64 	return w[propname].get!T;
65 }
66 
67 static T getPropertyAs(T)(string propname, FlexibleObject w, T defaultValue)
68 {
69 	if (auto property = propname in (cast(FlexibleObject)w).properties)
70 	{
71 		return property.get!T;
72 	}
73 	else
74 	{
75 		return defaultValue;
76 	}
77 }
78 
79 // ditto
80 static T getPropertyAs(string propname, T, FlexibleObjectType : FlexibleObject)(FlexibleObjectType w)
81 {
82 	static if(hasStaticProperty!(FlexibleObjectType, propname))
83 	{
84 		return mixin("w."~propname~".value.get!T");
85 	}
86 	else
87 	{
88 		return w[propname].get!T;
89 	}
90 }
91 
92 // ditto
93 static T getPropertyAs(string propname, T, FlexibleObjectType : FlexibleObject)(FlexibleObjectType w, T defaultValue)
94 {
95 	static if(hasStaticProperty!(FlexibleObjectType, propname))
96 	{
97 		return mixin("w."~propname~".value.get!T");
98 	}
99 	else
100 	{
101 		if (auto property = propname in (cast(FlexibleObject)w).properties)
102 		{
103 			return property.get!T;
104 		}
105 		else
106 		{
107 			return defaultValue;
108 		}
109 	}
110 }
111 
112 //
113 //
114 //
115 static T getPropertyAsBase(T)(string propname, FlexibleObject w)
116 {
117 	auto property = w[propname];
118 
119 	if (property.convertsTo!T)
120 		return property.get!T;
121 	else
122 		return null;
123 }
124 
125 // ditto
126 static T getPropertyAsBase(string propname, T, FlexibleObjectType : FlexibleObject)(FlexibleObjectType w)
127 {
128 	static if(hasStaticProperty!(FlexibleObjectType, propname))
129 	{
130 		auto property = mixin("w."~propname~".value");
131 	
132 		if (property.convertsTo!T)
133 			return property.get!T;
134 		else
135 			return null;
136 	}
137 	else
138 	{
139 		auto property = w[propname];
140 	
141 		if (property.convertsTo!T)
142 			return property.get!T;
143 		else
144 			return null;
145 	}
146 }
147 
148 
149 // Peek property value
150 static T* peekPropertyAs(T)(string propname, FlexibleObject w)
151 {
152 	return w[propname].peek!T;
153 }
154 
155 // ditto
156 static T* peekPropertyAs(string propname, T, FlexibleObjectType : FlexibleObject)(FlexibleObjectType w)
157 {
158 	static if(hasStaticProperty!(FlexibleObjectType, propname))
159 	{
160 		return mixin("w."~propname~".value.peek!T");
161 	}
162 	else
163 	{
164 		return w[propname].peek!T;
165 	}
166 }
167 
168 //
169 //
170 //
171 static T coercePropertyAs(T)(FlexibleObject w, string propname)
172 {
173 	return w[propname].coerce!T;
174 }
175 
176 static T coercePropertyAs(T)(FlexibleObject w, string propname, T defaultValue)
177 {
178 	if (auto property = propname in (cast(FlexibleObject)w).properties)
179 	{
180 		return property.value.coerce!T;
181 	}
182 	else
183 	{
184 		return defaultValue;
185 	}
186 }
187 
188 // ditto
189 static T coercePropertyAs(string propname, T, FlexibleObjectType : FlexibleObject)(FlexibleObjectType w)
190 {
191 	static if(hasStaticProperty!(FlexibleObjectType, propname))
192 	{
193 		return mixin("w."~propname~".value.coerce!T");
194 	}
195 	else
196 	{
197 		return w[propname].coerce!T;
198 	}
199 }
200 
201 // ditto
202 static T coercePropertyAs(string propname, T, FlexibleObjectType : FlexibleObject)(FlexibleObjectType w, T defaultValue)
203 {
204 	static if(hasStaticProperty!(FlexibleObjectType, propname))
205 	{
206 		return mixin("w."~propname~".value.coerce!T");
207 	}
208 	else
209 	{
210 		if (auto property = propname in (cast(FlexibleObject)w).properties)
211 		{
212 			return (*property).value.coerce!T;
213 		}
214 		else
215 		{
216 			return defaultValue;
217 		}
218 	}
219 }
220 
221 bool hasProperty(string propname, FlexibleObjectType : FlexibleObject)(FlexibleObjectType w)
222 {
223 	return (propname in (cast(FlexibleObject)w).properties) !is null;
224 }
225 
226 //
227 //
228 //
229 static void setProperty(ValueType)(FlexibleObject w, string propname, ValueType value)
230 {
231 	w[propname] = value;
232 }
233 
234 // ditto
235 static void setProperty(string propname, ValueType, FlexibleObjectType : FlexibleObject)(FlexibleObjectType w, ValueType value)
236 {
237 	static if(hasStaticProperty!(FlexibleObjectType, propname))
238 	{
239 		auto property = mixin("w."~propname);
240 
241 		static if (is(ValueType:Variant))
242 		{
243 			property.value = value;
244 		}
245 		else
246 		{
247 			property.value = Variant(value);
248 		}
249 	}
250 	else
251 	{
252 		static if (is(ValueType:Variant))
253 		{
254 			w[propname] = value;
255 		}
256 		else
257 		{
258 			w[propname] = Variant(value);
259 		}
260 	}
261 }
262 
263 // Binds property1 to property2. when property2 changes, property1 will be notified.
264 static void bindProperty(T1 : FlexibleObject, T2 : FlexibleObject)(T1 object1, string property1, T2 object2, string property2)
265 {
266 	assert(false);
267 }
268 // ditto
269 static void bindProperty(string property1, string property2, T1 : FlexibleObject, T2 : FlexibleObject)(FlexibleObject object1, FlexibleObject object2)
270 {
271 	assert(false);
272 }
273 // ditto
274 static void bindProperty(string property2, T1 : FlexibleObject, T2 : FlexibleObject)(FlexibleObject object1, string property1, FlexibleObject object2)
275 {
276 	assert(false);
277 }
278 // ditto
279 static void bindProperty(string property1, T1 : FlexibleObject, T2 : FlexibleObject)(FlexibleObject object1, FlexibleObject object2, string property2)
280 {
281 	assert(false);
282 }