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