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 <string>
6#include <algorithm>
7#include <unordered_map>
8
9#include "Prerequisites/BsPrerequisitesUtil.h"
10#include "Reflection/BsRTTIField.h"
11#include "Reflection/BsRTTIPlainField.h"
12#include "Reflection/BsRTTIReflectableField.h"
13#include "Reflection/BsRTTIReflectablePtrField.h"
14#include "Reflection/BsRTTIManagedDataBlockField.h"
15#include "Reflection/BsIReflectable.h"
16#include "Serialization/BsBinaryDiff.h"
17#include "Serialization/BsBinaryCompare.h"
18
19namespace bs
20{
21 /** @addtogroup RTTI
22 * @{
23 */
24
25 /**
26 * Starts definitions for member fields within a RTTI type. Follow this with calls to BS_RTTI_MEMBER* calls, and finish by
27 * calling BS_END_RTTI_MEMBERS.
28 */
29#define BS_BEGIN_RTTI_MEMBERS \
30 struct META_FirstEntry {}; \
31 void META_InitPrevEntry(META_FirstEntry typeId) { } \
32 \
33 typedef META_FirstEntry
34
35 /**
36 * Same as BS_RTTI_MEMBER_PLAIN, but allows you to specify separate names for the field name and the member variable,
37 * as well as an optional info structure further describing the field.
38 */
39#define BS_RTTI_MEMBER_PLAIN_FULL(name, field, id, info) \
40 META_Entry_##name; \
41 \
42 decltype(OwnerType::field)& get##name(OwnerType* obj) { return obj->field; } \
43 void set##name(OwnerType* obj, decltype(OwnerType::field)& val) { obj->field = val; } \
44 \
45 struct META_NextEntry_##name{}; \
46 void META_InitPrevEntry(META_NextEntry_##name typeId) \
47 { \
48 addPlainField(#name, id, &MyType::get##name, &MyType::set##name, info); \
49 META_InitPrevEntry(META_Entry_##name()); \
50 } \
51 \
52 typedef META_NextEntry_##name
53
54 /**
55 * Registers a new member field in the RTTI type. The field references the @p name member in the owner class.
56 * The type of the member must be a valid plain type. Each field must specify a unique ID for @p id.
57 * An optional @p RTTIFieldInfo structure can be provided to provide further information about the field.
58 */
59#define BS_RTTI_MEMBER_PLAIN(name, id) BS_RTTI_MEMBER_PLAIN_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT)
60
61 /** Same as BS_RTTI_MEMBER_PLAIN, but allows you to specify separate names for the field name and the member variable. */
62#define BS_RTTI_MEMBER_PLAIN_NAMED(name, field, id) BS_RTTI_MEMBER_PLAIN_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT)
63
64 /** Same as BS_RTTI_MEMBER_PLAIN, but allows you to specify an info structure that further describes the field. */
65#define BS_RTTI_MEMBER_PLAIN_INFO(name, id, info) BS_RTTI_MEMBER_PLAIN_FULL(name, name, id, info)
66
67 /**
68 * Same as BS_RTTI_MEMBER_PLAIN_ARRAY, but allows you to specify separate names for the field name and the member
69 * variable, as well as an optional info structure further describing the field.
70 */
71#define BS_RTTI_MEMBER_PLAIN_ARRAY_FULL(name, field, id, info) \
72 META_Entry_##name; \
73 \
74 std::common_type<decltype(OwnerType::field)>::type::value_type& get##name(OwnerType* obj, UINT32 idx) { return obj->field[idx]; } \
75 void set##name(OwnerType* obj, UINT32 idx, std::common_type<decltype(OwnerType::field)>::type::value_type& val) { obj->field[idx] = val; } \
76 UINT32 getSize##name(OwnerType* obj) { return (UINT32)obj->field.size(); } \
77 void setSize##name(OwnerType* obj, UINT32 val) { obj->field.resize(val); } \
78 \
79 struct META_NextEntry_##name{}; \
80 void META_InitPrevEntry(META_NextEntry_##name typeId) \
81 { \
82 addPlainArrayField(#name, id, &MyType::get##name, &MyType::getSize##name, &MyType::set##name, &MyType::setSize##name, info); \
83 META_InitPrevEntry(META_Entry_##name()); \
84 } \
85 \
86 typedef META_NextEntry_##name
87
88/**
89 * Registers a new member field in the RTTI type. The field references the @p name member in the owner class.
90 * The type of the member must be an array of valid plain types. Each field must specify a unique ID for @p id.
91 */
92#define BS_RTTI_MEMBER_PLAIN_ARRAY(name, id) BS_RTTI_MEMBER_PLAIN_ARRAY_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT)
93
94 /**
95 * Same as BS_RTTI_MEMBER_PLAIN_ARRAY, but allows you to specify separate names for the field name and the member variable.
96 */
97#define BS_RTTI_MEMBER_PLAIN_ARRAY_NAMED(name, field, id) BS_RTTI_MEMBER_PLAIN_ARRAY_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT)
98
99 /**
100 * Same as BS_RTTI_MEMBER_PLAIN_ARRAY, but allows you to specify an info structure that further describes the field.
101 */
102#define BS_RTTI_MEMBER_PLAIN_ARRAY_INFO(name, id, info) BS_RTTI_MEMBER_PLAIN_ARRAY_FULL(name, name, id, info)
103
104/**
105 * Same as BS_RTTI_MEMBER_REFL, but allows you to specify separate names for the field name and the member variable,
106 * as well as an optional info structure further describing the field.
107 */
108#define BS_RTTI_MEMBER_REFL_FULL(name, field, id, info) \
109 META_Entry_##name; \
110 \
111 decltype(OwnerType::field)& get##name(OwnerType* obj) { return obj->field; } \
112 void set##name(OwnerType* obj, decltype(OwnerType::field)& val) { obj->field = val; } \
113 \
114 struct META_NextEntry_##name{}; \
115 void META_InitPrevEntry(META_NextEntry_##name typeId) \
116 { \
117 addReflectableField(#name, id, &MyType::get##name, &MyType::set##name, info); \
118 META_InitPrevEntry(META_Entry_##name()); \
119 } \
120 \
121 typedef META_NextEntry_##name
122
123/**
124 * Registers a new member field in the RTTI type. The field references the @p name member in the owner class.
125 * The type of the member must be a valid reflectable (non-pointer) type. Each field must specify a unique ID for @p id.
126 */
127#define BS_RTTI_MEMBER_REFL(name, id) BS_RTTI_MEMBER_REFL_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT)
128
129/** Same as BS_RTTI_MEMBER_REFL, but allows you to specify separate names for the field name and the member variable. */
130#define BS_RTTI_MEMBER_REFL_NAMED(name, field, id) BS_RTTI_MEMBER_REFL_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT)
131
132/** Same as BS_RTTI_MEMBER_REFL, but allows you to specify an info structure that further describes the field. */
133#define BS_RTTI_MEMBER_REFL_INFO(name, id, info) BS_RTTI_MEMBER_REFL_FULL(name, name, id, info)
134
135/**
136 * Same as BS_RTTI_MEMBER_REFL_ARRAY, but allows you to specify separate names for the field name and the member variable,
137 * as well as an optional info structure further describing the field.
138 */
139#define BS_RTTI_MEMBER_REFL_ARRAY_FULL(name, field, id, info) \
140 META_Entry_##name; \
141 \
142 std::common_type<decltype(OwnerType::field)>::type::value_type& get##name(OwnerType* obj, UINT32 idx) { return obj->field[idx]; } \
143 void set##name(OwnerType* obj, UINT32 idx, std::common_type<decltype(OwnerType::field)>::type::value_type& val) { obj->field[idx] = val; } \
144 UINT32 getSize##name(OwnerType* obj) { return (UINT32)obj->field.size(); } \
145 void setSize##name(OwnerType* obj, UINT32 val) { obj->field.resize(val); } \
146 \
147 struct META_NextEntry_##name{}; \
148 void META_InitPrevEntry(META_NextEntry_##name typeId) \
149 { \
150 addReflectableArrayField(#name, id, &MyType::get##name, &MyType::getSize##name, &MyType::set##name, &MyType::setSize##name, info); \
151 META_InitPrevEntry(META_Entry_##name()); \
152 } \
153 \
154 typedef META_NextEntry_##name
155
156/**
157 * Registers a new member field in the RTTI type. The field references the @p name member in the owner class.
158 * The type of the member must be an array of valid reflectable (non-pointer) types. Each field must specify a unique ID for
159 * @p id.
160 */
161#define BS_RTTI_MEMBER_REFL_ARRAY(name, id) BS_RTTI_MEMBER_REFL_ARRAY_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT)
162
163/**
164 * Same as BS_RTTI_MEMBER_REFL_ARRAY, but allows you to specify separate names for the field name and the member variable.
165 */
166#define BS_RTTI_MEMBER_REFL_ARRAY_NAMED(name, field, id) BS_RTTI_MEMBER_REFL_ARRAY_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT)
167
168/**
169 * Same as BS_RTTI_MEMBER_REFL_ARRAY, but allows you to specify an info structure that further describes the field.
170 */
171#define BS_RTTI_MEMBER_REFL_ARRAY_INFO(name, id, info) BS_RTTI_MEMBER_REFL_ARRAY_FULL(name, name, id, info)
172
173/**
174 * Same as BS_RTTI_MEMBER_REFLPTR, but allows you to specify separate names for the field name and the member variable,
175 * as well as an optional info structure further describing the field.
176 */
177#define BS_RTTI_MEMBER_REFLPTR_FULL(name, field, id, info) \
178 META_Entry_##name; \
179 \
180 decltype(OwnerType::field) get##name(OwnerType* obj) { return obj->field; } \
181 void set##name(OwnerType* obj, decltype(OwnerType::field) val) { obj->field = val; } \
182 \
183 struct META_NextEntry_##name{}; \
184 void META_InitPrevEntry(META_NextEntry_##name typeId) \
185 { \
186 addReflectablePtrField(#name, id, &MyType::get##name, &MyType::set##name, info); \
187 META_InitPrevEntry(META_Entry_##name()); \
188 } \
189 \
190 typedef META_NextEntry_##name
191
192/**
193 * Registers a new member field in the RTTI type. The field references the @p name member in the owner class.
194 * The type of the member must be a valid reflectable pointer type. Each field must specify a unique ID for @p id.
195 */
196#define BS_RTTI_MEMBER_REFLPTR(name, id) BS_RTTI_MEMBER_REFLPTR_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT)
197
198/** Same as BS_RTTI_MEMBER_REFLPTR, but allows you to specify separate names for the field name and the member variable. */
199#define BS_RTTI_MEMBER_REFLPTR_NAMED(name, field, id) BS_RTTI_MEMBER_REFLPTR_FULL(name, field, id, RTTIFieldInfo::DEFAULT)
200
201/** Same as BS_RTTI_MEMBER_REFLPTR, but allows you to specify an info structure that further describes the field. */
202#define BS_RTTI_MEMBER_REFLPTR_INFO(name, id, info) BS_RTTI_MEMBER_REFLPTR_FULL(name, name, id, info)
203
204 /**
205 * Same as BS_RTTI_MEMBER_REFLPTR_ARRAY, but allows you to specify separate names for the field name and the member
206 * variable, as well as an optional info structure further describing the field.
207 */
208#define BS_RTTI_MEMBER_REFLPTR_ARRAY_FULL(name, field, id, info) \
209 META_Entry_##name; \
210 \
211 std::common_type<decltype(OwnerType::field)>::type::value_type get##name(OwnerType* obj, UINT32 idx) { return obj->field[idx]; } \
212 void set##name(OwnerType* obj, UINT32 idx, std::common_type<decltype(OwnerType::field)>::type::value_type val) { obj->field[idx] = val; } \
213 UINT32 getSize##name(OwnerType* obj) { return (UINT32)obj->field.size(); } \
214 void setSize##name(OwnerType* obj, UINT32 val) { obj->field.resize(val); } \
215 \
216 struct META_NextEntry_##name{}; \
217 void META_InitPrevEntry(META_NextEntry_##name typeId) \
218 { \
219 addReflectablePtrArrayField(#name, id, &MyType::get##name, &MyType::getSize##name, &MyType::set##name, &MyType::setSize##name, info); \
220 META_InitPrevEntry(META_Entry_##name()); \
221 } \
222 \
223 typedef META_NextEntry_##name
224
225/**
226 * Registers a new member field in the RTTI type. The field references the @p name member in the owner class.
227 * The type of the member must be a valid reflectable pointer type. Each field must specify a unique ID for @p id.
228 */
229#define BS_RTTI_MEMBER_REFLPTR_ARRAY(name, id) BS_RTTI_MEMBER_REFLPTR_ARRAY_FULL(name, name, id, bs::RTTIFieldInfo::DEFAULT)
230
231 /**
232 * Same as BS_RTTI_MEMBER_REFLPTR_ARRAY, but allows you to specify separate names for the field name and the member
233 * variable.
234 */
235#define BS_RTTI_MEMBER_REFLPTR_ARRAY_NAMED(name, field, id) BS_RTTI_MEMBER_REFLPTR_ARRAY_FULL(name, field, id, bs::RTTIFieldInfo::DEFAULT)
236
237 /** Same as BS_RTTI_MEMBER_REFLPTR_ARRAY, but allows you to specify an info structure that further describes the field. */
238#define BS_RTTI_MEMBER_REFLPTR_ARRAY_INFO(name, id, info) BS_RTTI_MEMBER_REFLPTR_ARRAY_FULL(name, name, id, info)
239
240/** Ends definitions for member fields with a RTTI type. Must follow BS_BEGIN_RTTI_MEMBERS. */
241#define BS_END_RTTI_MEMBERS \
242 META_LastEntry; \
243 \
244 struct META_InitAllMembers \
245 { \
246 META_InitAllMembers(MyType* owner) \
247 { \
248 static bool sMembersInitialized = false; \
249 if(!sMembersInitialized) \
250 { \
251 owner->META_InitPrevEntry(META_LastEntry()); \
252 sMembersInitialized = true; \
253 } \
254 } \
255 }; \
256 \
257 META_InitAllMembers mInitMembers{this};
258
259 /** @} */
260
261 /** @addtogroup Internal-Utility
262 * @{
263 */
264 /** @addtogroup RTTI-Internal
265 * @{
266 */
267
268 struct SerializationContext;
269
270 /**
271 * Provides an interface for accessing fields of a certain class.
272 * Data can be easily accessed by getter and setter methods.
273 *
274 * Supported data types:
275 * - Plain types - All types defined in BsRTTIField.h, mostly native types and POD (plain old data) structs. Data is parsed byte by byte.
276 * No pointers to plain types are supported. Data is passed around by value.
277 * - Reflectable types - Any class deriving from IReflectable. Data is parsed based on fields in its RTTI class. Can be pointer or value type.
278 * - Arrays of both plain and reflectable types are supported
279 * - Data blocks - A managed or unmanaged block of data. See ManagedDataBlock.
280 */
281 class BS_UTILITY_EXPORT RTTITypeBase
282 {
283 public:
284 RTTITypeBase() = default;
285 virtual ~RTTITypeBase();
286
287 /** Returns RTTI type information for all classes that derive from the class that owns this RTTI type. */
288 virtual Vector<RTTITypeBase*>& getDerivedClasses() = 0;
289
290 /**
291 * Returns RTTI type information for the class that owns this RTTI type. If the class has not base type, null is
292 * returned instead.
293 */
294 virtual RTTITypeBase* getBaseClass() = 0;
295
296 /** Returns true if current RTTI class is derived from @p base. (Or if it is the same type as base) */
297 virtual bool isDerivedFrom(RTTITypeBase* base) = 0;
298
299 /** Creates a new instance of the class owning this RTTI type. */
300 virtual SPtr<IReflectable> newRTTIObject() = 0;
301
302 /** Returns the name of the class owning this RTTI type. */
303 virtual const String& getRTTIName() = 0;
304
305 /** Returns an RTTI id that uniquely represents each class in the RTTI system. */
306 virtual UINT32 getRTTIId() = 0;
307
308 /**
309 * Called by the serializers when serialization for this object has started. Use this to do any preprocessing on
310 * data you might need during serialization itself.
311 */
312 virtual void onSerializationStarted(IReflectable* obj, SerializationContext* context) {}
313
314 /**
315 * Called by the serializers when serialization for this object has ended. After serialization has ended you can
316 * be sure that the type has been fully serialized, and you may clean up any temporary data.
317 */
318 virtual void onSerializationEnded(IReflectable* obj, SerializationContext* context) {}
319
320 /**
321 * Called by the serializers when deserialization for this object has started. Use this to do any preprocessing
322 * on data you might need during deserialization itself.
323 */
324 virtual void onDeserializationStarted(IReflectable* obj, SerializationContext* context) {}
325
326 /**
327 * Called by the serializers when deserialization for this object has ended. At this point you can be sure the
328 * instance has been fully deserialized and you may safely use it.
329 *
330 * One exception being are fields you marked with RTTI_Flag_WeakRef, as they might be resolved only after
331 * deserialization has fully completed for all objects.
332 */
333 virtual void onDeserializationEnded(IReflectable* obj, SerializationContext* context) {}
334
335 /**
336 * Returns a handler that determines how are "diffs" generated and applied when it comes to objects of this RTTI
337 * type. A "diff" is a list of differences between two objects that may be saved, viewed or applied to another
338 * object to transform it.
339 */
340 virtual IDiff& getDiffHandler() const
341 {
342 static BinaryDiff diffHandler;
343 return diffHandler;
344 }
345
346 /** Returns a handler that determines how are IReflectable objects compared for equality. */
347 virtual ICompare& getCompareHandler() const
348 {
349 static BinaryCompare compareHandler;
350 return compareHandler;
351 }
352
353 /** Returns the total number of fields in this RTTI type. */
354 UINT32 getNumFields() const { return (UINT32)mFields.size(); }
355
356 /** Returns a field based on the field index. Use getNumFields() to get total number of fields available. */
357 RTTIField* getField(UINT32 idx) { return mFields.at(idx); }
358
359 /**
360 * Tries to find a field with the specified name. Throws an exception if it can't.
361 *
362 * @param name The name of the field.
363 */
364 RTTIField* findField(const String& name);
365
366 /**
367 * Tries to find a field with the specified unique ID. Doesn't throw an exception if it can't find the field
368 * (Unlike findField(const String&)).
369 *
370 * @param uniqueFieldId Unique identifier for the field.
371 *
372 * @return nullptr if it can't find the field.
373 */
374 RTTIField* findField(int uniqueFieldId);
375
376 /** @name Internal
377 * @{
378 */
379
380 /** Called by the RTTI system when a class is first found in order to form child/parent class hierarchy. */
381 virtual void _registerDerivedClass(RTTITypeBase* derivedClass) = 0;
382
383 /**
384 * Constucts a cloned version of the underlying class. The cloned version will not have any field information and
385 * should instead be used for passing to various RTTIField methods during serialization/deserialization. This
386 * allows each object instance to have a unique places to store temporary instance-specific data.
387 */
388 virtual RTTITypeBase* _clone(FrameAlloc& alloc) = 0;
389
390 /** @} */
391
392 protected:
393 /**
394 * Tries to add a new field to the fields array, and throws an exception if a field with the same name or id
395 * already exists.
396 *
397 * @param[in] field Field, must be non-null.
398 */
399 void addNewField(RTTIField* field);
400
401 private:
402 Vector<RTTIField*> mFields;
403 };
404
405 /** Used for initializing a certain type as soon as the program is loaded. */
406 template<typename Type, typename BaseType>
407 struct InitRTTIOnStart
408 {
409 public:
410 InitRTTIOnStart()
411 {
412 IReflectable::_registerRTTIType(Type::getRTTIStatic());
413 BaseType::getRTTIStatic()->_registerDerivedClass(Type::getRTTIStatic());
414 }
415
416 void makeSureIAmInstantiated() { }
417 };
418
419 /** Specialization for root class of RTTI hierarchy - IReflectable */
420 template<typename Type>
421 struct InitRTTIOnStart<Type, IReflectable>
422 {
423 public:
424 InitRTTIOnStart()
425 {
426 IReflectable::_registerRTTIType(Type::getRTTIStatic());
427 }
428
429 void makeSureIAmInstantiated() { }
430 };
431
432 /**
433 * Template that returns RTTI type of the specified type, unless the specified type is IReflectable in which case it
434 * returns a null.
435 */
436 template<typename Type>
437 struct GetRTTIType
438 {
439 RTTITypeBase* operator()() { return Type::getRTTIStatic(); }
440 };
441
442 /** Specialization for root class of RTTI hierarchy - IReflectable. */
443 template<>
444 struct GetRTTIType<IReflectable>
445 {
446 RTTITypeBase* operator()() { return nullptr; }
447 };
448
449 /** @} */
450 /** @} */
451
452 /** @addtogroup RTTI
453 * @{
454 */
455
456 /**
457 * Allows you to provide a run-time type information for a specific class, along with support for
458 * serialization/deserialization.
459 *
460 * Derive from this class and return the that class from IReflectable::getRTTI. This way you can separate serialization
461 * logic from the actual class you're serializing.
462 *
463 * This class will provide a way to register individual fields in the class, together with ways to read and write them,
464 * as well a providing information about class hierarchy, and run-time type checking.
465 */
466 template <typename Type, typename BaseType, typename MyRTTIType>
467 class RTTIType : public RTTITypeBase
468 {
469 protected:
470 /************************************************************************/
471 /* RTTI CLASS META DATA */
472 /************************************************************************/
473
474 static InitRTTIOnStart<Type, BaseType> initOnStart;
475
476 public:
477 RTTIType()
478 {
479 // Compiler will only generate code for stuff that is directly used, including static data members,
480 // so we fool it here like we're using the class directly. Otherwise compiler won't generate the code for the member
481 // and our type won't get initialized on start (Actual behavior is a bit more random)
482 initOnStart.makeSureIAmInstantiated();
483 }
484 virtual ~RTTIType() = default;
485
486 /** Returns a singleton of this RTTI type. */
487 static MyRTTIType* instance()
488 {
489 static MyRTTIType inst;
490 return &inst;
491 }
492
493 /** @copydoc RTTITypeBase::getDerivedClasses */
494 Vector<RTTITypeBase*>& getDerivedClasses() override
495 {
496 static Vector<RTTITypeBase*> mRTTIDerivedClasses;
497 return mRTTIDerivedClasses;
498 }
499
500 /** @copydoc RTTITypeBase::getBaseClass */
501 RTTITypeBase* getBaseClass() override
502 {
503 return GetRTTIType<BaseType>()();
504 }
505
506 /** @copydoc RTTITypeBase::isDerivedFrom */
507 bool isDerivedFrom(RTTITypeBase* base) override
508 {
509 assert(base != nullptr);
510
511 Stack<RTTITypeBase*> todo;
512 todo.push(base);
513
514 while (!todo.empty())
515 {
516 RTTITypeBase* currentType = todo.top();
517 todo.pop();
518
519 if (currentType->getRTTIId() == getRTTIId())
520 return true;
521
522 for (const auto& item : currentType->getDerivedClasses())
523 todo.push(item);
524 }
525
526 return false;
527 }
528
529 /** @copydoc RTTITypeBase::_registerDerivedClass */
530 void _registerDerivedClass(RTTITypeBase* derivedClass) override
531 {
532 getDerivedClasses().push_back(derivedClass);
533 }
534
535 /** @copydoc RTTITypeBase::_clone */
536 RTTITypeBase* _clone(FrameAlloc& alloc) override
537 {
538 return alloc.construct<MyRTTIType>();
539 }
540
541 protected:
542 typedef Type OwnerType;
543 typedef MyRTTIType MyType;
544
545 /** Registers a field referencing a plain type. */
546 template<class InterfaceType, class ObjectType, class DataType>
547 void addPlainField(const String& name, UINT32 uniqueId,
548 DataType& (InterfaceType::*getter)(ObjectType*),
549 void (InterfaceType::*setter)(ObjectType*, DataType&),
550 const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT)
551 {
552 static_assert((std::is_base_of<bs::RTTIType<Type, BaseType, MyRTTIType>, InterfaceType>::value),
553 "Class with the get/set methods must derive from bs::RTTIType.");
554
555 static_assert(!(std::is_base_of<bs::IReflectable, DataType>::value),
556 "Data type derives from IReflectable but it is being added as a plain field.");
557
558 auto newField = bs_new<RTTIPlainField<InterfaceType, DataType, ObjectType>>();
559 newField->initSingle(name, uniqueId, getter, setter, info);
560 addNewField(newField);
561 }
562
563 /** Registers a field referencing an IReflectable type passed by value. */
564 template<class InterfaceType, class ObjectType, class DataType>
565 void addReflectableField(const String& name, UINT32 uniqueId,
566 DataType& (InterfaceType::*getter)(ObjectType*),
567 void (InterfaceType::*setter)(ObjectType*, DataType&),
568 const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT)
569 {
570 static_assert((std::is_base_of<bs::IReflectable, DataType>::value),
571 "Invalid data type for complex field. It needs to derive from bs::IReflectable.");
572
573 auto newField = bs_new<RTTIReflectableField<InterfaceType, DataType, ObjectType>>();
574 newField->initSingle(name, uniqueId, getter, setter, info);
575 addNewField(newField);
576 }
577
578 /** Registers a field referencing an IReflectable type passed by pointer. */
579 template<class InterfaceType, class ObjectType, class DataType>
580 void addReflectablePtrField(const String& name, UINT32 uniqueId,
581 SPtr<DataType> (InterfaceType::*getter)(ObjectType*),
582 void (InterfaceType::*setter)(ObjectType*, SPtr<DataType>),
583 const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT)
584 {
585 static_assert((std::is_base_of<bs::IReflectable, DataType>::value),
586 "Invalid data type for complex field. It needs to derive from bs::IReflectable.");
587
588 auto newField = bs_new<RTTIReflectablePtrField<InterfaceType, DataType, ObjectType>>();
589 newField->initSingle(name, uniqueId, getter, setter, info);
590 addNewField(newField);
591 }
592
593 /** Registers a field referencing an array of plain types. */
594 template<class InterfaceType, class ObjectType, class DataType>
595 void addPlainArrayField(const String& name, UINT32 uniqueId,
596 DataType& (InterfaceType::*getter)(ObjectType*, UINT32),
597 UINT32(InterfaceType::*getSize)(ObjectType*),
598 void (InterfaceType::*setter)(ObjectType*, UINT32, DataType&),
599 void(InterfaceType::*setSize)(ObjectType*, UINT32),
600 const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT)
601 {
602 static_assert((std::is_base_of<bs::RTTIType<Type, BaseType, MyRTTIType>, InterfaceType>::value),
603 "Class with the get/set methods must derive from bs::RTTIType.");
604
605 static_assert(!(std::is_base_of<bs::IReflectable, DataType>::value),
606 "Data type derives from IReflectable but it is being added as a plain field.");
607
608 auto newField = bs_new<RTTIPlainField<InterfaceType, DataType, ObjectType>>();
609 newField->initArray(name, uniqueId, getter, getSize, setter, setSize, info);
610 addNewField(newField);
611 }
612
613 /** Registers a field referencing an array of IReflectable objects. */
614 template<class InterfaceType, class ObjectType, class DataType>
615 void addReflectableArrayField(const String& name, UINT32 uniqueId,
616 DataType& (InterfaceType::*getter)(ObjectType*, UINT32),
617 UINT32 (InterfaceType::*getSize)(ObjectType*),
618 void (InterfaceType::*setter)(ObjectType*, UINT32, DataType&),
619 void(InterfaceType::*setSize)(ObjectType*, UINT32),
620 const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT)
621 {
622 static_assert((std::is_base_of<bs::IReflectable, DataType>::value),
623 "Invalid data type for complex field. It needs to derive from bs::IReflectable.");
624
625 auto newField = bs_new<RTTIReflectableField<InterfaceType, DataType, ObjectType>>();
626 newField->initArray(name, uniqueId, getter, getSize, setter, setSize, info);
627 addNewField(newField);
628 }
629
630 /** Registers a field referencing an array of IReflectable pointers. */
631 template<class InterfaceType, class ObjectType, class DataType>
632 void addReflectablePtrArrayField(const String& name, UINT32 uniqueId,
633 SPtr<DataType> (InterfaceType::*getter)(ObjectType*, UINT32),
634 UINT32 (InterfaceType::*getSize)(ObjectType*),
635 void (InterfaceType::*setter)(ObjectType*, UINT32, SPtr<DataType>),
636 void(InterfaceType::*setSize)(ObjectType*, UINT32),
637 const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT)
638 {
639 static_assert((std::is_base_of<bs::IReflectable, DataType>::value),
640 "Invalid data type for complex field. It needs to derive from bs::IReflectable.");
641
642 auto newField = bs_new<RTTIReflectablePtrField<InterfaceType, DataType, ObjectType>>();
643 newField->initArray(name, uniqueId, getter, getSize, setter, setSize, info);
644 addNewField(newField);
645 }
646
647 /** Registers a field referencing a blob of memory. */
648 template<class InterfaceType, class ObjectType>
649 void addDataBlockField(const String& name, UINT32 uniqueId, SPtr<DataStream> (InterfaceType::*getter)(ObjectType*, UINT32&),
650 void (InterfaceType::*setter)(ObjectType*, const SPtr<DataStream>&, UINT32),
651 const RTTIFieldInfo& info = RTTIFieldInfo::DEFAULT)
652 {
653 auto newField = bs_new<RTTIManagedDataBlockField<InterfaceType, UINT8*, ObjectType>>();
654 newField->initSingle(name, uniqueId, getter, setter, info);
655 addNewField(newField);
656 }
657 };
658
659 template <typename Type, typename BaseType, typename MyRTTIType>
660 InitRTTIOnStart<Type, BaseType> RTTIType<Type, BaseType, MyRTTIType>::initOnStart;
661
662 /** Extendable class to be used by the user to provide extra information to RTTIType objects during serialization. */
663 struct BS_UTILITY_EXPORT SerializationContext : IReflectable
664 {
665 UINT32 flags = 0;
666
667 static RTTITypeBase* getRTTIStatic();
668 RTTITypeBase* getRTTI() const override;
669 };
670
671 /** Returns true if the provided object can be safely cast into type T. */
672 template<class T>
673 bool rtti_is_of_type(IReflectable* object)
674 {
675 static_assert((std::is_base_of<bs::IReflectable, T>::value),
676 "Invalid data type for type checking. It needs to derive from bs::IReflectable.");
677
678 return object->getTypeId() == T::getRTTIStatic()->getRTTIId();
679 }
680
681 /** Returns true if the provided object can be safely cast into type T. */
682 template<class T>
683 bool rtti_is_of_type(SPtr<IReflectable> object)
684 {
685 static_assert((std::is_base_of<bs::IReflectable, T>::value),
686 "Invalid data type for type checking. It needs to derive from bs::IReflectable.");
687
688 return object->getTypeId() == T::getRTTIStatic()->getRTTIId();
689 }
690
691 /** Creates a new object just from its type ID. */
692 BS_UTILITY_EXPORT SPtr<IReflectable> rtti_create(UINT32 rttiId);
693
694 /** Checks is the current object a subclass of some type. */
695 template<class T>
696 bool rtti_is_subclass(IReflectable* object)
697 {
698 static_assert((std::is_base_of<bs::IReflectable, T>::value),
699 "Invalid data type for type checking. It needs to derive from bs::IReflectable.");
700
701 return object && object->isDerivedFrom(T::getRTTIStatic());
702 }
703
704 /** Checks is the current object a subclass of some type. */
705 template<class T>
706 bool rtti_is_subclass(const SPtr<IReflectable>& object)
707 {
708 static_assert((std::is_base_of<bs::IReflectable, T>::value),
709 "Invalid data type for type checking. It needs to derive from bs::IReflectable.");
710
711 return object && object->isDerivedFrom(T::getRTTIStatic());
712 }
713
714 /** Attempts to cast the object to the provided type, or returns null if cast is not valid. */
715 template<class T>
716 T* rtti_cast(IReflectable* object)
717 {
718 if(rtti_is_subclass<T>(object))
719 return (T*)object;
720
721 return nullptr;
722 }
723
724 /** Attempts to cast the object to the provided type, or returns null if cast is not valid. */
725 template<class T>
726 SPtr<T> rtti_cast(const SPtr<IReflectable> object)
727 {
728 if(rtti_is_subclass<T>(object))
729 return std::static_pointer_cast<T>(object);
730
731 return nullptr;
732 }
733 /** @} */
734}
735