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