1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "Prerequisites/BsPrerequisitesUtil.h"
6#include "Reflection/BsRTTIField.h"
7#include "Error/BsException.h"
8
9namespace bs
10{
11 /** @addtogroup Internal-Utility
12 * @{
13 */
14
15 /** @addtogroup RTTI-Internal
16 * @{
17 */
18
19 /**
20 * Base class containing common functionality for a plain class field.
21 *
22 * @note
23 * Plain fields are considered those that may be serialized directly by copying their memory. (All built-in types,
24 * strings, etc.)
25 */
26 struct RTTIPlainFieldBase : public RTTIField
27 {
28 virtual ~RTTIPlainFieldBase() = default;
29
30 /** Throws an exception if the current field type and provided template types don't match. */
31 template<class DataType>
32 void checkType()
33 {
34 // TODO: Low priority. Because I wanted to get rid of SerializableType I have no way of checking the actual
35 // type of the field and the type provided to get/set methods matches
36
37 /*if(mType.id != SerializableType<DataType>().id)
38 {
39 BS_EXCEPT(InternalErrorException,
40 "Invalid field type.",
41 "SerializableSimpleTypeFieldBase::checkType()");
42 }*/
43 }
44
45 /** Returns the unique identifier for the type owned by the field. */
46 virtual UINT32 getTypeId()
47 {
48 return 0;
49 }
50
51 /** @copydoc RTTIField::hasDynamicSize */
52 bool hasDynamicSize() override
53 {
54 return false;
55 }
56
57 /** Gets the dynamic size of the object. If object has no dynamic size, static size of the object is returned. */
58 virtual UINT32 getDynamicSize(RTTITypeBase* rtti, void* object)
59 {
60 return 0;
61 }
62
63 /**
64 * Gets the dynamic size of an array element. If the element has no dynamic size, static size of the element
65 * is returned.
66 */
67 virtual UINT32 getArrayElemDynamicSize(RTTITypeBase* rtti, void* object, int index)
68 {
69 return 0;
70 }
71
72 /**
73 * Retrieves the value from the provided field of the provided object, and copies it into the buffer. It does not
74 * check if buffer is large enough.
75 */
76 virtual void toBuffer(RTTITypeBase* rtti, void* object, void* buffer) = 0;
77
78 /**
79 * Retrieves the value at the specified array index on the provided field of the provided object, and copies it into
80 * the buffer. It does not check if buffer is large enough.
81 */
82 virtual void arrayElemToBuffer(RTTITypeBase* rtti, void* object, int index, void* buffer) = 0;
83
84 /**
85 * Sets the value on the provided field of the provided object. Value is copied from the buffer. It does not check
86 * the value in the buffer in any way. You must make sure buffer points to the proper location and contains the
87 * proper type.
88 */
89 virtual void fromBuffer(RTTITypeBase* rtti, void* object, void* buffer) = 0;
90
91 /**
92 * Sets the value at the specified array index on the provided field of the provided object. Value is copied from
93 * the buffer. It does not check the value in the buffer in any way. You must make sure buffer points to the proper
94 * location and contains the proper type.
95 */
96 virtual void arrayElemFromBuffer(RTTITypeBase* rtti, void* object, int index, void* buffer) = 0;
97 };
98
99 /** Represents a plain class field containing a specific type. */
100 template <class InterfaceType, class DataType, class ObjectType>
101 struct RTTIPlainField : public RTTIPlainFieldBase
102 {
103 typedef DataType& (InterfaceType::*GetterType)(ObjectType*);
104 typedef void (InterfaceType::*SetterType)(ObjectType*, DataType&);
105
106 typedef DataType& (InterfaceType::*ArrayGetterType)(ObjectType*, UINT32);
107 typedef void (InterfaceType::*ArraySetterType)(ObjectType*, UINT32, DataType&);
108 typedef UINT32(InterfaceType::*ArrayGetSizeType)(ObjectType*);
109 typedef void(InterfaceType::*ArraySetSizeType)(ObjectType*, UINT32);
110
111 /**
112 * Initializes a plain field containing a single value.
113 *
114 * @param[in] name Name of the field.
115 * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a
116 * small data type that can be used for efficiently serializing data to disk and similar.
117 * It is primarily used for compatibility between different versions of serialized data.
118 * @param[in] getter The getter method for the field.
119 * @param[in] setter The setter method for the field.
120 * @param[in] info Various optional information about the field.
121 */
122 void initSingle(String name, UINT16 uniqueId, GetterType getter, SetterType setter, const RTTIFieldInfo& info)
123 {
124 static_assert(sizeof(RTTIPlainType<DataType>::id) > 0, "Type has no RTTI ID."); // Just making sure provided type has a type ID
125
126 static_assert((RTTIPlainType<DataType>::hasDynamicSize != 0 || (sizeof(DataType) <= 255)),
127 "Trying to create a plain RTTI field with size larger than 255. In order to use larger sizes for plain types please specialize " \
128 " RTTIPlainType, set hasDynamicSize to true.");
129
130 this->getter = getter;
131 this->setter = setter;
132
133 init(std::move(name), uniqueId, false, SerializableFT_Plain, info);
134 }
135
136 /**
137 * Initializes a plain field containing multiple values in an array.
138 *
139 * @param[in] name Name of the field.
140 * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a
141 * small data type that can be used for efficiently serializing data to disk and similar.
142 * It is primarily used for compatibility between different versions of serialized data.
143 * @param[in] getter The getter method for the field.
144 * @param[in] getSize Getter method that returns the size of an array.
145 * @param[in] setter The setter method for the field.
146 * @param[in] setSize Setter method that allows you to resize an array. Can be null.
147 * @param[in] info Various optional information about the field.
148 */
149 void initArray(String name, UINT16 uniqueId, ArrayGetterType getter,
150 ArrayGetSizeType getSize, ArraySetterType setter, ArraySetSizeType setSize, const RTTIFieldInfo& info)
151 {
152 static_assert((RTTIPlainType<DataType>::id != 0) || true, ""); // Just making sure provided type has a type ID
153
154 static_assert((RTTIPlainType<DataType>::hasDynamicSize != 0 || (sizeof(DataType) <= 255)),
155 "Trying to create a plain RTTI field with size larger than 255. In order to use larger sizes for plain types please specialize " \
156 " RTTIPlainType, set hasDynamicSize to true.");
157
158 arrayGetter = getter;
159 arraySetter = setter;
160 arrayGetSize = getSize;
161 arraySetSize = setSize;
162
163 init(std::move(name), uniqueId, true, SerializableFT_Plain, info);
164 }
165
166 /** @copydoc RTTIField::getTypeSize */
167 UINT32 getTypeSize() override
168 {
169 return sizeof(DataType);
170 }
171
172 /** @copydoc RTTIPlainFieldBase::getTypeId */
173 UINT32 getTypeId() override
174 {
175 return RTTIPlainType<DataType>::id;
176 }
177
178 /** @copydoc RTTIPlainFieldBase::hasDynamicSize */
179 bool hasDynamicSize() override
180 {
181 return RTTIPlainType<DataType>::hasDynamicSize != 0;
182 }
183
184 /** @copydoc RTTIPlainFieldBase::getDynamicSize */
185 UINT32 getDynamicSize(RTTITypeBase* rtti, void* object) override
186 {
187 checkIsArray(false);
188 checkType<DataType>();
189
190 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
191 ObjectType* castObject = static_cast<ObjectType*>(object);
192 DataType value = (rttiObject->*getter)(castObject);
193
194 return RTTIPlainType<DataType>::getDynamicSize(value);
195 }
196
197 /** @copydoc RTTIPlainFieldBase::getArrayElemDynamicSize */
198 UINT32 getArrayElemDynamicSize(RTTITypeBase* rtti, void* object, int index) override
199 {
200 checkIsArray(true);
201 checkType<DataType>();
202
203 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
204 ObjectType* castObject = static_cast<ObjectType*>(object);
205 DataType value = (rttiObject->*arrayGetter)(castObject, index);
206
207 return RTTIPlainType<DataType>::getDynamicSize(value);
208 }
209
210 /** Returns the size of the array managed by the field. */
211 UINT32 getArraySize(RTTITypeBase* rtti, void* object) override
212 {
213 checkIsArray(true);
214
215 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
216 ObjectType* castObject = static_cast<ObjectType*>(object);
217 return (rttiObject->*arrayGetSize)(castObject);
218 }
219
220 /** Changes the size of the array managed by the field. Array must be re-populated after. */
221 void setArraySize(RTTITypeBase* rtti, void* object, UINT32 size) override
222 {
223 checkIsArray(true);
224
225 if(!arraySetSize)
226 {
227 BS_EXCEPT(InternalErrorException, "Specified field (" + mName + ") has no array size setter.");
228 }
229
230 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
231 ObjectType* castObject = static_cast<ObjectType*>(object);
232 (rttiObject->*arraySetSize)(castObject, size);
233 }
234
235 /** @copydoc RTTIPlainFieldBase::toBuffer */
236 void toBuffer(RTTITypeBase* rtti, void* object, void* buffer) override
237 {
238 checkIsArray(false);
239 checkType<DataType>();
240
241 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
242 ObjectType* castObject = static_cast<ObjectType*>(object);
243 DataType value = (rttiObject->*getter)(castObject);
244
245 RTTIPlainType<DataType>::toMemory(value, (char*)buffer);
246 }
247
248 /** @copydoc RTTIPlainFieldBase::arrayElemToBuffer */
249 void arrayElemToBuffer(RTTITypeBase* rtti, void* object, int index, void* buffer) override
250 {
251 checkIsArray(true);
252 checkType<DataType>();
253
254 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
255 ObjectType* castObject = static_cast<ObjectType*>(object);
256 DataType value = (rttiObject->*arrayGetter)(castObject, index);
257
258 RTTIPlainType<DataType>::toMemory(value, (char*)buffer);
259 }
260
261 /** @copydoc RTTIPlainFieldBase::fromBuffer */
262 void fromBuffer(RTTITypeBase* rtti, void* object, void* buffer) override
263 {
264 checkIsArray(false);
265 checkType<DataType>();
266
267 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
268 ObjectType* castObject = static_cast<ObjectType*>(object);
269
270 DataType value;
271 RTTIPlainType<DataType>::fromMemory(value, (char*)buffer);
272
273 if(!setter)
274 {
275 BS_EXCEPT(InternalErrorException,
276 "Specified field (" + mName + ") has no setter.");
277 }
278
279 (rttiObject->*setter)(castObject, value);
280 }
281
282 /** @copydoc RTTIPlainFieldBase::arrayElemFromBuffer */
283 void arrayElemFromBuffer(RTTITypeBase* rtti, void* object, int index, void* buffer) override
284 {
285 checkIsArray(true);
286 checkType<DataType>();
287
288 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
289 ObjectType* castObject = static_cast<ObjectType*>(object);
290
291 DataType value;
292 RTTIPlainType<DataType>::fromMemory(value, (char*)buffer);
293
294 if(!arraySetter)
295 {
296 BS_EXCEPT(InternalErrorException,
297 "Specified field (" + mName + ") has no setter.");
298 }
299
300 (rttiObject->*arraySetter)(castObject, index, value);
301 }
302
303 private:
304 union
305 {
306 struct
307 {
308 GetterType getter;
309 SetterType setter;
310 };
311
312 struct
313 {
314 ArrayGetterType arrayGetter;
315 ArraySetterType arraySetter;
316
317 ArrayGetSizeType arrayGetSize;
318 ArraySetSizeType arraySetSize;
319 };
320 };
321 };
322
323 /** @} */
324 /** @} */
325}
326