#pragma once #include "reflection/Property.h" #include "reflection/Function.h" #include "reflection/YieldFunction.h" #include "Reflection/Event.h" #include "reflection/Callback.h" #include #include "boost/crc.hpp" namespace RBX { namespace Reflection { enum ReplicationLevel{ NEVER_REPLICATE = 0, //Never replicate this object STANDARD_REPLICATE= 1, //Replicate to/from server according to standard rules PLAYER_REPLICATE = 2, //Replicate changes to/from the "player" who owns this object } ; class ClassDescriptor : public Descriptor , public MemberDescriptorContainer , public MemberDescriptorContainer , public MemberDescriptorContainer , public MemberDescriptorContainer , public MemberDescriptorContainer { public: typedef std::vector ClassDescriptors; enum Functionality{ PERSISTENT = 0x1 + 0x2 + 0x8 + 0x10, // isPublic, Replicate, canXmlWrite, isScriptable PERSISTENT_PLAYER = 0x1 + 0x4 + 0x8 + 0x10, // isPublic, ReplicatePlayer, canXmlWrite, isScriptable PERSISTENT_LOCAL = 0x1 + 0x0 + 0x8 + 0x10, // isPublic, canXmlWrite, isScriptable RUNTIME = 0x1 + 0x2 + 0x0 + 0x10, // isPublic, Replicate, isScriptable RUNTIME_PLAYER = 0x1 + 0x4 + 0x0 + 0x10, // isPublic, ReplicatePlayer, isScriptable RUNTIME_LOCAL = 0x1 + 0x0 + 0x0 + 0x10, // isPublic, isScriptable INTERNAL = 0x1 + 0x2 + 0x0 + 0x0, // isPublic, Replicate INTERNAL_PLAYER = 0x1 + 0x4 + 0x0 + 0x0, // isPublic, ReplicatePlayer, INTERNAL_LOCAL = 0x1 + 0x0 + 0x0 + 0x0, // isPublic PERSISTENT_HIDDEN = 0x1 + 0x2 + 0x8 + 0x0, // isPublic, Replicate, canXmlWrite PERSISTENT_LOCAL_INTERNAL = 0x1 + 0x0 + 0x8 + 0x0, // isPublic, canXmlWrite }; struct Attributes : public Descriptor::Attributes { Functionality flags; Attributes(Functionality flags):flags(flags) {} static Attributes deprecated(Functionality flags, const ClassDescriptor* preferred); }; const Security::Permissions security; private: ClassDescriptor(); static ClassDescriptors& allClasses(); ClassDescriptors derivedClasses; ClassDescriptor* const base; const unsigned bReplicateType : 2; const unsigned bCanXmlWrite : 1; const unsigned bIsScriptable : 1; static int count; public: ClassDescriptor(ClassDescriptor& base, const char* name, Attributes attributes, Security::Permissions security); ~ClassDescriptor() { count--; } const ClassDescriptor* getBase() const { return base; } bool isBaseOf(const ClassDescriptor& child) const; bool isA(const ClassDescriptor& test) const; bool isBaseOf(const char* childName) const; bool isA(const char* testName) const; inline ReplicationLevel getReplicationLevel() const { return (ReplicationLevel)bReplicateType; } inline bool isScriptCreatable() const { return bIsScriptable != 0; } inline bool isSerializable() const { return bCanXmlWrite != 0; } // The root ClassDescriptor of all other Descriptors static ClassDescriptor& rootDescriptor() { static ClassDescriptor root; return root; } ///////////////////////////////////////////////////////////////////////////////// // Class enumeration static ClassDescriptors::const_iterator all_begin() { return allClasses().begin(); } static ClassDescriptors::const_iterator all_end() { return allClasses().end(); } static size_t all_size() { return allClasses().size(); } static unsigned int checksum(); static unsigned int checksum(const PropertyDescriptor* t, boost::crc_32_type& result); static unsigned int checksum(const EventDescriptor* t, boost::crc_32_type& result); static unsigned int checksum(const ClassDescriptor* t, boost::crc_32_type& result); static unsigned int checksum(const Type* t, boost::crc_32_type& result); ///////////////////////////////////////////////////////////////////////////////// // Derived Class enumeration ClassDescriptors::const_iterator derivedClasses_begin() const { return derivedClasses.begin(); } ClassDescriptors::const_iterator derivedClasses_end() const { return derivedClasses.end(); } ///////////////////////////////////////////////////////////////////////////////// // Convenience functions for enumerating and querying members of a Class PropertyDescriptor* findPropertyDescriptor(const char* name) const { return MemberDescriptorContainer::findDescriptor(name); } FunctionDescriptor* findFunctionDescriptor(const char* name) const { return MemberDescriptorContainer::findDescriptor(name); } YieldFunctionDescriptor* findYieldFunctionDescriptor(const char* name) const { return MemberDescriptorContainer::findDescriptor(name); } EventDescriptor* findEventDescriptor(const char* name) const { return MemberDescriptorContainer::findDescriptor(name); } CallbackDescriptor* findCallbackDescriptor(const char* name) const { return MemberDescriptorContainer::findDescriptor(name); } template typename MemberDescriptorContainer::Collection::const_iterator begin() const { return MemberDescriptorContainer::descriptors_begin(); } template typename MemberDescriptorContainer::Collection::const_iterator end() const { return MemberDescriptorContainer::descriptors_end(); } bool operator==(const ClassDescriptor& other) const; bool operator!=(const ClassDescriptor& other) const; }; // Convenience typedefs: typedef MemberDescriptorContainer::ConstIterator ConstPropertyIterator; typedef MemberDescriptorContainer::Iterator PropertyIterator; typedef MemberDescriptorContainer::ConstIterator FunctionIterator; typedef MemberDescriptorContainer::ConstIterator YieldFunctionIterator; typedef MemberDescriptorContainer::ConstIterator ConstSignalIterator; typedef MemberDescriptorContainer::Iterator SignalIterator; typedef MemberDescriptorContainer::Iterator CallbackIterator; // The base class of any class that supports Reflection class RBXBaseClass DescribedBase : public EventSource , public boost::enable_shared_from_this { protected: // Each instance has a reference to it's most-specific ClassDescriptor: const ClassDescriptor* descriptor; boost::scoped_ptr xmlId; public: // The ClassDescriptor for this base class static ClassDescriptor& classDescriptor() { return ClassDescriptor::rootDescriptor(); } DescribedBase() { Descriptor::lockedDown = true; // See Descriptor::checkLockedDown() for an explanation // By default, each DescribedBase has a null ClassDescriptor this->descriptor = &classDescriptor(); } virtual ~DescribedBase() { } inline const ClassDescriptor& getDescriptor() const { return *descriptor; }; template inline bool isA() const { return getDescriptor().isA(T::classDescriptor()); } template static inline bool isA(const DescribedBase* instance) { return instance ? instance->getDescriptor().isA(T::classDescriptor()) : false; } // This function is slower than the others bool isA(std::string className) { return getDescriptor().isA(className.c_str()); } // Regular dynamic_casts are very slow. These faster versions uses our reflection framework to determine type then uses static_cast for speed. // Use these functions to replace dynamic_casts for classes that derives from DescribedCreatable or DescribedNonCreatable. template inline T* fastDynamicCast() { return (getDescriptor().isA(T::classDescriptor())) ? static_cast(this) : NULL; } template inline const T* fastDynamicCast() const { return (getDescriptor().isA(T::classDescriptor())) ? static_cast(this) : NULL; } template static inline T* fastDynamicCast(DescribedBase* instance) { return (instance && instance->getDescriptor().isA(T::classDescriptor())) ? static_cast(instance) : NULL; } template static inline const T* fastDynamicCast(const DescribedBase* instance) { return (instance && instance->getDescriptor().isA(T::classDescriptor())) ? static_cast(instance) : NULL; } // This function replaces shared_dynamic_cast for classes that derives from DescribedCreatable or DescribedNonCreatable. template static inline shared_ptr fastSharedDynamicCast(const shared_ptr& instance) { return isA(instance.get()) ? shared_static_cast(instance) : shared_ptr(); } ///////////////////////////////////////////////////////////////////////////////// // Convenience functions for getting members of a described object PropertyDescriptor* findPropertyDescriptor(const char* name) { return getDescriptor().MemberDescriptorContainer::findDescriptor(name); } ConstPropertyIterator properties_begin() const { return getDescriptor().MemberDescriptorContainer::members_begin(this); } ConstPropertyIterator properties_end() const { return getDescriptor().MemberDescriptorContainer::members_end(this); } PropertyIterator properties_begin() { return getDescriptor().MemberDescriptorContainer::members_begin(this); } PropertyIterator properties_end() { return getDescriptor().MemberDescriptorContainer::members_end(this); } FunctionDescriptor* findFunctionDescriptor(const char* name) { return getDescriptor().MemberDescriptorContainer::findDescriptor(name); } FunctionIterator functions_begin() const { return getDescriptor().MemberDescriptorContainer::members_begin(this); } FunctionIterator functions_end() const { return getDescriptor().MemberDescriptorContainer::members_end(this); } YieldFunctionDescriptor* findYieldFunctionDescriptor(const char* name) const { return getDescriptor().MemberDescriptorContainer::findDescriptor(name); } YieldFunctionIterator yield_functions_begin() const { return getDescriptor().MemberDescriptorContainer::members_begin(this); } YieldFunctionIterator yield_functions_end() const { return getDescriptor().MemberDescriptorContainer::members_end(this); } CallbackDescriptor* findCallbackDescriptor(const char* name) { return getDescriptor().MemberDescriptorContainer::findDescriptor(name); } CallbackIterator callbacks_begin() { return getDescriptor().MemberDescriptorContainer::members_begin(this); } CallbackIterator callbacks_end() { return getDescriptor().MemberDescriptorContainer::members_end(this); } EventDescriptor* findSignalDescriptor(const char* name) const { return getDescriptor().MemberDescriptorContainer::findDescriptor(name); } ConstSignalIterator signals_begin() const { return getDescriptor().MemberDescriptorContainer::members_begin(this); } ConstSignalIterator signals_end() const { return getDescriptor().MemberDescriptorContainer::members_end(this); } SignalIterator signals_begin() { return getDescriptor().MemberDescriptorContainer::members_begin(this); } SignalIterator signals_end() { return getDescriptor().MemberDescriptorContainer::members_end(this); } const std::string* getXmlId() const { return xmlId.get(); } void setXmlId(const std::string& newId) { if (!xmlId) { xmlId.reset(new std::string(newId)); } else { *xmlId = newId; } } virtual const RBX::Name& getClassName() const = 0; }; } }