Cogs.Foundation
Loading...
Searching...
No Matches
Reflection

This functionality can be used to add simple reflection capabilities to C++ code without special compiler support and/or post-processing of the compiled output.

The reflection API gives the user a TypeDatabase static class to manage instances of the Type class.

Usage

Reflection is enabled for all Cogs Entities, Components, Fields and Enums.

The reflection type database requires unique names for all types added. Field reflection is handled locally for each Component to allow same name in several Components.

Reflection is used to generate interface classes to Cogs in languages like C++, C#, Typescript/JavasScript and Python. It is also used by the Cogs Debug GUI to display and edit contents of Cogs Entities.

See existing code for patterns of how to add reflection to Cogs types.

Adding a range of a component field can be useful for entity editors. For example limiting a rotation angle to 0..2PI. The range is only a hint and not used in any field value setting checking.

For interface code generation doxygen type code documentation of data types and enum values will be parsed and used.

When adding new types to the code, include types in Cogs.Core code-generation and check result.

Adding reflection for a C++ class

#include <Foundation/ComponentModel/Component.h>
#include <Foundation/Reflection/TypeDatabase.h>
using namespace Cogs::Reflection;
namespace MyDefs {
class MyComponent : public Cogs::ComponentModel::Component
{
public:
// Reflection classes must have default constructor.
MyComponent() = default;
static void registerType();
bool visible = true;
};
}
template<> Cogs::StringView getName<MyDefs::MyComponent>() { return "MyComponent"; }
Base class for Component instances.
Definition: Component.h:143
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
Contains reflection support.
Definition: Component.h:11
void MyDefs::MyComponent::registerType()
{
{ "visible", &MyDefs::MyComponent::visible },
};
// Register type.
Cogs::Reflection::TypeDatabase::createType<MyComponent>()
// Name of base class.
.setBase<Component>()
// Register the component fields.
.setFields(fields);
}
Field definition describing a single data member of a data structure.
Definition: Field.h:68

Adding reflection for a C++ enum

Showing an enum storing a bitmask of values. The doxygen style documentation of the enum is used when generating language bindings for C#, TypeScript etc.

namespace Cogs::Core
{
enum class PickingFlags : uint32_t {
None = 0,
PickSprites = 1 << 0,
ReturnChildEntity = 1 << 1,
RemoveDuplicateEntities = 1 << 2,
};
// Adds custom and/or operators for the enum
ENABLE_ENUM_FLAGS(PickingFlags);
}

Adding reflection for enum is done at system or extension initialization.

#include <Foundation/Reflection/TypeDatabase.h>
// Use EnumeratorDef to allow compile-time initialization.
static constexpr EnumeratorDef pickingEnums[] = {
{ "None", PickingFlags::None },
{ "PickSprites", PickingFlags::PickSprites },
{ "ReturnChildEntity", PickingFlags::ReturnChildEntity },
{ "RemoveDuplicateEntities", PickingFlags::RemoveDuplicateEntities },
};
// Register enum type for reflection
TypeDatabase::createType<PickingFlags>()
// Inform type system that it is an enum and add value reflection
.setEnumerators(pickingEnums)
// Optional: Mark enum is a bit-mask
.setEnumFlags();
Definition: Type.h:27

Using reflection to lookup and instantiate a type

#include <Foundation/Reflection/TypeDatabase.h>
using namespace Cogs::Reflection;
void useReflection()
{
const Type & type = TypeDatabase::getType("MyComponent");
// Check that value and not Enumeration
assert(type.isValid());
assert(!type.isEnum());
// Expect class to inherit from "Component" - not handling several levels.
const Type * base = type.getBase();
assert(base);
assert(base->getName() == "Component");
// Use the type here
...
}
void createInstance()
{
// The type of the returned pointer will be cast to the
// given template type.
//
ComponentModel::Component* instance = TypeDatabase::createInstance<ComponentModel::Component>("MyComponent");
}
Represents a discrete type definition, describing a native type class.
Definition: Type.h:89
const Type * getBase() const
Get the base type.
Definition: Type.cpp:32
bool isEnum() const
Get if the type is an enumeration type.
Definition: Type.h:315
constexpr const Name & getName() const
Get the unique name of the type.
Definition: Type.h:198
constexpr bool isValid() const
Gets if the type is considered a valid, registered type.
Definition: Type.h:328

Using reflection find contents of a Cogs Entity

For example usage see Cogs.Codegenerator or Cogs Debug GUI EntityInspector.

{c++}
auto def = context->store->getEntityDefinition("Cube");
// Loop through components:
for (auto& c : def.components) {
const auto& type = TypeDatabase::getType(c);
auto numFields = c.getNumFields();
for (Reflection::FieldId i = 0; i < numFields; ++i) {
const auto& field = *type.getField(i);
if (fieldType.isEnum()) {
// Reflect on the enum type
}
}
}