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 | |
9 | namespace 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 | } |