1 /**
2 License:
3 Boost Software License - Version 1.0 - August 17th, 2003
4 5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license (the "Software") to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 27 Authors:
28 Alexandru Ermicioi
29 **/30 moduleaermicioi.aedi_property_reader.core.setter;
31 32 importaermicioi.aedi : NotFoundException;
33 importaermicioi.aedi_property_reader.core.exception;
34 importaermicioi.aedi_property_reader.core.convertor;
35 importaermicioi.aedi_property_reader.core.placeholder;
36 importaermicioi.util.traits : isPublic, isField;
37 importaermicioi.aedi_property_reader.core.traits;
38 importstd.conv;
39 importstd.traits;
40 importstd.meta;
41 importstd.exception;
42 43 /**
44 Provides ability to set a property of FieldType into CompositeType.
45 **/46 interfacePropertySetter(CompositeType, FieldType = CompositeType, KeyType = string) {
47 48 /**
49 Set a field or property of CompositeType.
50 51 Params:
52 composite = composite that will store value
53 value = actual value that is assigned to a field in composite
54 property = the identity of field in composite
55 Throws:
56 InvalidArgumentException when value or composite is not what was expected
57 **/58 voidset(refCompositeTypecomposite, FieldTypevalue, KeyTypeproperty) const;
59 60 /**
61 Identify the type of supported component.
62 63 Identify the type of supported component. It returns type info of component
64 if it is supported by accessor, otherwise it will return typeid(void) denoting that
65 the type isn't supported by accessor. The accessor is not limited to returning the type
66 info of passed component, it can actually return type info of super type or any type
67 given the returned type is implicitly convertible or castable to ComponentType.
68 69 Params:
70 component = the component for which accessor should identify the underlying type
71 72 Returns:
73 TypeInfo type information about passed component, or typeid(void) if component is not supported.
74 **/75 TypeInfocomponentType(refCompositeTypecomposite) constnothrow;
76 77 /**
78 Identify the type of supported component.
79 80 Identify the type of supported component. It returns type info of component
81 if it is supported by accessor, otherwise it will return typeid(void) denoting that
82 the type isn't supported by accessor. The accessor is not limited to returning the type
83 info of passed component, it can actually return type info of super type or any type
84 given the returned type is implicitly convertible or castable to ComponentType.
85 86 Params:
87 component = the component for which accessor should identify the underlying type
88 89 Returns:
90 TypeInfo type information about passed component, or typeid(void) if component is not supported.
91 **/92 finalTypeInfocomponentType(CompositeTypecomposite) constnothrow {
93 returnthis.componentType(composite);
94 }
95 }
96 97 /**
98 Associative array setter.
99 **/100 classAssociativeArraySetter(Type, KeyType = Type) : PropertySetter!(Type[KeyType], Type, KeyType) {
101 102 public {
103 /**
104 Set a field or property of CompositeType.
105 106 Params:
107 composite = composite that will store value
108 value = actual value that is assigned to a field in composite
109 property = the identity of field in composite
110 Throws:
111 InvalidArgumentException when value or composite is not what was expected
112 **/113 voidset(refType[KeyType] composite, Typefield, KeyTypekey) const {
114 composite[key] = field;
115 }
116 117 /**
118 Identify the type of supported component.
119 120 Identify the type of supported component. It returns type info of component
121 if it is supported by accessor, otherwise it will return typeid(void) denoting that
122 the type isn't supported by accessor. The accessor is not limited to returning the type
123 info of passed component, it can actually return type info of super type or any type
124 given the returned type is implicitly convertible or castable to ComponentType.
125 126 Params:
127 component = the component for which accessor should identify the underlying type
128 129 Returns:
130 TypeInfo type information about passed component, or typeid(void) if component is not supported.
131 **/132 TypeInfocomponentType(refType[KeyType] composite) constnothrow {
133 returntypeid(Type[KeyType]);
134 }
135 }
136 }
137 138 /**
139 Array setter.
140 **/141 classArraySetter(Type) : PropertySetter!(Type[], Type, size_t) {
142 143 /**
144 Set a field or property of CompositeType.
145 146 Params:
147 composite = composite that will store value
148 value = actual value that is assigned to a field in composite
149 property = the identity of field in composite
150 Throws:
151 InvalidArgumentException when value or composite is not what was expected
152 **/153 voidset(refType[] composite, Typefield, size_tkey) const {
154 enforce!InvalidArgumentException(key < composite.length, text(
155 "Cannot assign ",
156 field,
157 " to ",
158 composite,
159 " index ",
160 key,
161 " out of bounds ",
162 composite.length163 ));
164 165 composite[key] = field;
166 }
167 168 /**
169 Identify the type of supported component.
170 171 Identify the type of supported component. It returns type info of component
172 if it is supported by accessor, otherwise it will return typeid(void) denoting that
173 the type isn't supported by accessor. The accessor is not limited to returning the type
174 info of passed component, it can actually return type info of super type or any type
175 given the returned type is implicitly convertible or castable to ComponentType.
176 177 Params:
178 component = the component for which accessor should identify the underlying type
179 180 Returns:
181 TypeInfo type information about passed component, or typeid(void) if component is not supported.
182 **/183 TypeInfocomponentType(refType[] composite) constnothrow {
184 returntypeid(Type[]);
185 }
186 }
187 188 /**
189 Composite (object, struct, union) setter.
190 **/191 classCompositeSetter(ComponentType) : PropertySetter!(ComponentType, Object, string)
192 if (isAggregateType!ComponentType) {
193 194 /**
195 Set a field or property of CompositeType.
196 197 Params:
198 composite = composite that will store value
199 value = actual value that is assigned to a field in composite
200 property = the identity of field in composite
201 Throws:
202 InvalidArgumentException when value or composite is not what was expected
203 **/204 voidset(T)(refComponentTypecomponent, Tfield, stringproperty) const {
205 importstd.experimental.allocator : theAllocator, dispose;
206 autowrapped = field.placeholder(theAllocator);
207 this.set(component, wrapped, property);
208 209 staticif (!is(T : Object)) {
210 theAllocator.dispose(wrapped);
211 }
212 }
213 214 /**
215 ditto
216 **/217 voidset(refComponentTypecomponent, Objectfield, stringproperty) const {
218 staticforeach (member; __traits(allMembers, ComponentType)) {{
219 staticif (isPublic!(ComponentType, member)) {
220 aliasm = Alias!(__traits(getMember, component, member));
221 222 if (member == property) {
223 staticif (isField!(ComponentType, member)) {
224 aliasFieldType = typeof(__traits(getMember, component, member));
225 226 enforce!InvalidArgumentException(field.identifyistypeid(FieldType), text(
227 "Cannot set value of type ", field.identify,
228 " to property ", member,
229 " of type ", typeid(FieldType)
230 ));
231 232 __traits(getMember, component, member) = field.unwrap!FieldType;
233 return;
234 } elsestaticif (
235 isSomeFunction!m &&
236 anySatisfy!(isPropertyPropertySetter, __traits(getOverloads, ComponentType, member))
237 ) {
238 aliasFieldType = Parameters!(
239 match!(
240 isPropertyPropertySetter,
241 __traits(getOverloads, ComponentType, member)
242 )
243 )[0];
244 245 enforce!InvalidArgumentException(field.identifyistypeid(FieldType), text(
246 "Cannot set value of type ", field.identify,
247 " to property ", member,
248 " of type ", typeid(FieldType)
249 ));
250 251 __traits(getMember, component, member) = field.unwrap!FieldType;
252 return;
253 }
254 }
255 }
256 }}
257 258 thrownewNotFoundException(text(
259 "Component of type ",
260 typeid(ComponentType),
261 " does not have ",
262 property,
263 " property"264 ));
265 }
266 267 /**
268 Identify the type of supported component.
269 270 Identify the type of supported component. It returns type info of component
271 if it is supported by accessor, otherwise it will return typeid(void) denoting that
272 the type isn't supported by accessor. The accessor is not limited to returning the type
273 info of passed component, it can actually return type info of super type or any type
274 given the returned type is implicitly convertible or castable to ComponentType.
275 276 Params:
277 component = the component for which accessor should identify the underlying type
278 279 Returns:
280 TypeInfo type information about passed component, or typeid(void) if component is not supported.
281 **/282 TypeInfocomponentType(refComponentTypecomposite) constnothrow {
283 returntypeid(ComponentType);
284 }
285 }
286 287 /**
288 Runtime composite setter that accepts erased Type, restores it's type and sets data in it.
289 **/290 classRuntimeCompositeSetter(Type, FieldType = Type, KeyType = string) : PropertySetter!(Object, FieldType, KeyType) {
291 private {
292 PropertySetter!(Type, FieldType, KeyType) setter_;
293 }
294 295 public {
296 /**
297 Constructor for runtime composite setter.
298 299 Params:
300 setter = underlying setter used for assigning fields to component
301 **/302 this(PropertySetter!(Type, FieldType, KeyType) setter) {
303 this.setter = setter;
304 }
305 306 @property {
307 /**
308 Set setter
309 310 Params:
311 setter = underlying setter used to set data
312 313 Returns:
314 typeof(this)
315 **/316 typeof(this) setter(PropertySetter!(Type, FieldType, KeyType) setter) @safenothrowpure {
317 this.setter_ = setter;
318 319 returnthis;
320 }
321 322 /**
323 Get setter
324 325 Returns:
326 PropertySetter!(Type, FieldType, KeyType)
327 **/328 inout(PropertySetter!(Type, FieldType, KeyType)) setter() @safenothrowpureinout {
329 returnthis.setter_;
330 }
331 }
332 333 /**
334 Set a field or property of CompositeType.
335 336 Params:
337 composite = composite that will store value
338 value = actual value that is assigned to a field in composite
339 property = the identity of field in composite
340 Throws:
341 InvalidArgumentException when value or composite is not what was expected
342 **/343 voidset(refObjectcomposite, FieldTypefield, KeyTypekey) const {
344 autoplaceholder = composite.unwrap!Type;
345 this.setter.set(placeholder, field, key);
346 }
347 348 /**
349 Identify the type of supported component.
350 351 Identify the type of supported component. It returns type info of component
352 if it is supported by accessor, otherwise it will return typeid(void) denoting that
353 the type isn't supported by accessor. The accessor is not limited to returning the type
354 info of passed component, it can actually return type info of super type or any type
355 given the returned type is implicitly convertible or castable to ComponentType.
356 357 Params:
358 component = the component for which accessor should identify the underlying type
359 360 Returns:
361 TypeInfo type information about passed component, or typeid(void) if component is not supported.
362 **/363 TypeInfocomponentType(refObjectcomposite) constnothrow {
364 if (composite.identifyistypeid(Type)) {
365 returnthis.setter.componentType(composite.unwrap!Type);
366 }
367 368 returntypeid(void);
369 }
370 }
371 }
372 373 /**
374 Runtime field setter that accepts type erased fields, that are restored and then assigned to component.
375 **/376 classRuntimeFieldSetter(Type, FieldType = Type, KeyType = string) : PropertySetter!(Type, Object, KeyType) {
377 private {
378 PropertySetter!(Type, FieldType, KeyType) setter_;
379 }
380 381 public {
382 /**
383 Constructor for runtime field setter.
384 385 Params:
386 setter = underlying setter that works directly with FieldType values
387 **/388 this(PropertySetter!(Type, FieldType, KeyType) setter) {
389 this.setter = setter;
390 }
391 392 @property {
393 /**
394 Set setter
395 396 Params:
397 setter = underlying setter used to set data
398 399 Returns:
400 typeof(this)
401 **/402 typeof(this) setter(PropertySetter!(Type, FieldType, KeyType) setter) @safenothrowpure {
403 this.setter_ = setter;
404 405 returnthis;
406 }
407 408 /**
409 Get setter
410 411 Returns:
412 PropertySetter!(Type, FieldType, KeyType)
413 **/414 inout(PropertySetter!(Type, FieldType, KeyType)) setter() @safenothrowpureinout {
415 returnthis.setter_;
416 }
417 }
418 419 /**
420 Set a field or property of CompositeType.
421 422 Params:
423 composite = composite that will store value
424 value = actual value that is assigned to a field in composite
425 property = the identity of field in composite
426 Throws:
427 InvalidArgumentException when value or composite is not what was expected
428 **/429 voidset(refTypecomposite, Objectfield, KeyTypekey) const {
430 this.setter.set(composite, field.unwrap!FieldType, key);
431 }
432 433 /**
434 Identify the type of supported component.
435 436 Identify the type of supported component. It returns type info of component
437 if it is supported by accessor, otherwise it will return typeid(void) denoting that
438 the type isn't supported by accessor. The accessor is not limited to returning the type
439 info of passed component, it can actually return type info of super type or any type
440 given the returned type is implicitly convertible or castable to ComponentType.
441 442 Params:
443 component = the component for which accessor should identify the underlying type
444 445 Returns:
446 TypeInfo type information about passed component, or typeid(void) if component is not supported.
447 **/448 TypeInfocomponentType(refTypecomposite) constnothrow {
449 returntypeid(Type);
450 }
451 }
452 }