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