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 "Reflection/BsIReflectable.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 reflectable pointer class field.
21 *
22 * @note
23 * Reflectable fields are fields containing complex types deriving from IReflectable. They are serialized recursively
24 * and you may add/remove fields from them without breaking the serialized data.
25 * @note
26 * ReflectablePtr fields are different from Reflectable fields because other types may reference the same Reflectable
27 * object using a ReflectablePtr, while normal Reflectable fields are only referenced by a single field they're declared on.
28 */
29 struct RTTIReflectablePtrFieldBase : public RTTIField
30 {
31 /**
32 * Retrieves the IReflectable value from the provided instance.
33 *
34 * @note Field type must not be an array.
35 */
36 virtual SPtr<IReflectable> getValue(RTTITypeBase* rtti, void* object) = 0;
37
38 /**
39 * Retrieves the IReflectable value from an array on the provided instance and index.
40 *
41 * @note Field type must be an array.
42 */
43 virtual SPtr<IReflectable> getArrayValue(RTTITypeBase* rtti, void* object, UINT32 index) = 0;
44
45 /**
46 * Sets the IReflectable value in the provided instance.
47 *
48 * @note Field type must not be an array.
49 */
50 virtual void setValue(RTTITypeBase* rtti, void* object, SPtr<IReflectable> value) = 0;
51
52 /**
53 * Sets the IReflectable value in an array on the provided instance and index.
54 *
55 * @note Field type must be an array.
56 */
57 virtual void setArrayValue(RTTITypeBase* rtti, void* object, UINT32 index, SPtr<IReflectable> value) = 0;
58
59 /** Creates a new object of the field type. */
60 virtual SPtr<IReflectable> newObject() = 0;
61
62 /** Returns the RTTI identifier of the class owning the field. */
63 virtual UINT32 getRTTIId() = 0;
64
65 /** Returns the name of the class owning the field. */
66 virtual const String& getRTTIName() = 0;
67
68 /** @copydoc RTTIField::hasDynamicSize */
69 bool hasDynamicSize() override { return true; }
70
71 /** Retrieves the RTTI object for the type the field contains. */
72 virtual RTTITypeBase* getType() = 0;
73 };
74
75 /** Reflectable field containing a pointer to a specific type with RTTI implemented. */
76 template <class InterfaceType, class DataType, class ObjectType>
77 struct RTTIReflectablePtrField : public RTTIReflectablePtrFieldBase
78 {
79 typedef SPtr<DataType> (InterfaceType::*GetterType)(ObjectType*);
80 typedef void (InterfaceType::*SetterType)(ObjectType*, SPtr<DataType>);
81
82 typedef SPtr<DataType> (InterfaceType::*ArrayGetterType)(ObjectType*, UINT32);
83 typedef void (InterfaceType::*ArraySetterType)(ObjectType*, UINT32, SPtr<DataType>);
84 typedef UINT32(InterfaceType::*ArrayGetSizeType)(ObjectType*);
85 typedef void(InterfaceType::*ArraySetSizeType)(ObjectType*, UINT32);
86
87 /**
88 * Initializes a field pointing to a single data type implementing IReflectable interface.
89 *
90 * @param[in] name Name of the field.
91 * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a
92 * small data type that can be used for efficiently serializing data to disk and similar.
93 * It is primarily used for compatibility between different versions of serialized data.
94 * @param[in] getter The getter method for the field.
95 * @param[in] setter The setter method for the field.
96 * @param[in] info Various optional information about the field.
97 */
98 void initSingle(String name, UINT16 uniqueId, GetterType getter, SetterType setter, const RTTIFieldInfo& info)
99 {
100 this->getter = getter;
101 this->setter = setter;
102
103 init(std::move(name), uniqueId, false, SerializableFT_ReflectablePtr, info);
104 }
105
106 /**
107 * Initializes a field containing an array of pointers to data types implementing IReflectable interface.
108 *
109 * @param[in] name Name of the field.
110 * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a
111 * small data type that can be used for efficiently serializing data to disk and similar.
112 * It is primarily used for compatibility between different versions of serialized data.
113 * @param[in] getter The getter method for the field.
114 * @param[in] getSize Getter method that returns the size of an array.
115 * @param[in] setter The setter method for the field.
116 * @param[in] setSize Setter method that allows you to resize an array. Can be null.
117 * @param[in] info Various optional information about the field.
118 */
119 void initArray(String name, UINT16 uniqueId, ArrayGetterType getter, ArrayGetSizeType getSize,
120 ArraySetterType setter, ArraySetSizeType setSize, const RTTIFieldInfo& info)
121 {
122 arrayGetter = getter;
123 arraySetter = setter;
124 arrayGetSize = getSize;
125 arraySetSize = setSize;
126
127 init(std::move(name), uniqueId, true, SerializableFT_ReflectablePtr, info);
128 }
129
130 /** @copydoc RTTIField::getTypeSize */
131 UINT32 getTypeSize() override
132 {
133 return 0; // Complex types don't store size the conventional way
134 }
135
136 /** @copydoc RTTIReflectablePtrFieldBase::getValue */
137 SPtr<IReflectable> getValue(RTTITypeBase* rtti, void* object) override
138 {
139 checkIsArray(false);
140
141 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
142 ObjectType* castObjType = static_cast<ObjectType*>(object);
143
144 SPtr<IReflectable> castDataType = (rttiObject->*getter)(castObjType);
145 return castDataType;
146 }
147
148 /** @copydoc RTTIReflectablePtrFieldBase::getArrayValue */
149 SPtr<IReflectable> getArrayValue(RTTITypeBase* rtti, void* object, UINT32 index) override
150 {
151 checkIsArray(true);
152
153 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
154 ObjectType* castObjType = static_cast<ObjectType*>(object);
155
156 SPtr<IReflectable> castDataType = (rttiObject->*arrayGetter)(castObjType, index);
157 return castDataType;
158 }
159
160 /** @copydoc RTTIReflectablePtrFieldBase::setValue */
161 void setValue(RTTITypeBase* rtti, void* object, SPtr<IReflectable> value) override
162 {
163 checkIsArray(false);
164
165 if(!setter)
166 {
167 BS_EXCEPT(InternalErrorException,
168 "Specified field (" + mName + ") has no setter.");
169 }
170
171 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
172 ObjectType* castObjType = static_cast<ObjectType*>(object);
173 SPtr<DataType> castDataObj = std::static_pointer_cast<DataType>(value);
174
175 (rttiObject->*setter)(castObjType, castDataObj);
176 }
177
178 /** @copydoc RTTIReflectablePtrFieldBase::setArrayValue */
179 void setArrayValue(RTTITypeBase* rtti, void* object, UINT32 index, SPtr<IReflectable> value) override
180 {
181 checkIsArray(true);
182
183 if(!arraySetter)
184 {
185 BS_EXCEPT(InternalErrorException,
186 "Specified field (" + mName + ") has no setter.");
187 }
188
189 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
190 ObjectType* castObjType = static_cast<ObjectType*>(object);
191 SPtr<DataType> castDataObj = std::static_pointer_cast<DataType>(value);
192
193 (rttiObject->*arraySetter)(castObjType, index, castDataObj);
194 }
195
196 /** @copydoc RTTIField::setArraySize */
197 UINT32 getArraySize(RTTITypeBase* rtti, void* object) override
198 {
199 checkIsArray(true);
200
201 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
202 ObjectType* castObject = static_cast<ObjectType*>(object);
203
204 return (rttiObject->*arrayGetSize)(castObject);
205 }
206
207 /** @copydoc RTTIField::setArraySize */
208 void setArraySize(RTTITypeBase* rtti, void* object, UINT32 size) override
209 {
210 checkIsArray(true);
211
212 if(!arraySetSize)
213 {
214 BS_EXCEPT(InternalErrorException,
215 "Specified field (" + mName + ") has no array size setter.");
216 }
217
218 InterfaceType* rttiObject = static_cast<InterfaceType*>(rtti);
219 ObjectType* castObject = static_cast<ObjectType*>(object);
220
221 (rttiObject->*arraySetSize)(castObject, size);
222 }
223
224 /** @copydoc RTTIReflectablePtrFieldBase::newObject */
225 SPtr<IReflectable> newObject() override
226 {
227 return SPtr<IReflectable>(DataType::getRTTIStatic()->newRTTIObject());
228 }
229
230 /** @copydoc RTTIReflectablePtrFieldBase::getRTTIId */
231 UINT32 getRTTIId() override
232 {
233 return DataType::getRTTIStatic()->getRTTIId();
234 }
235
236 /** @copydoc RTTIReflectablePtrFieldBase::getRTTIName */
237 const String& getRTTIName() override
238 {
239 return DataType::getRTTIStatic()->getRTTIName();
240 }
241
242
243 /** @copydoc RTTIReflectablePtrFieldBase::getType */
244 RTTITypeBase* getType() override
245 {
246 return DataType::getRTTIStatic();
247 }
248
249 private:
250 union
251 {
252 struct
253 {
254 GetterType getter;
255 SetterType setter;
256 };
257
258 struct
259 {
260 ArrayGetterType arrayGetter;
261 ArraySetterType arraySetter;
262
263 ArrayGetSizeType arrayGetSize;
264 ArraySetSizeType arraySetSize;
265 };
266 };
267 };
268
269 /** @} */
270 /** @} */
271}