Home

Awesome

<div align="center"> <img src="Docs/rfk-logo.svg" width=300>

License: MIT Latest Release codecov documentation

Windows Linux MacOS

</div>

Overview

Refureku is a powerful C++17 runtime reflection dynamic library.
It is split in 2 parts:

Check the Wiki to get started!

Features

Design goals

Refureku was initially developed with game engine development in mind, which greatly influenced the global design and architecture. The usage was mostly inspired by UE4, and the API by the C# native reflection system.

The concept is simple: you write what you want to reflect once, include the generated files, and the code generator does the rest. Users don't have any extra step to care about. Reflected entities are automatically registered to the reflection system and available right away. Manual reflection was an absolute no-go because it is error prone and time-consuming.

Another point addressed by this library is the reflection syntax. It is sometimes annoying to be tied to the macro syntax of a third party library, especially when it is heavily used accross a project. Using Refureku x Kodgen, the user has full control over the generated files / macros names to make the reflection integrate well in any project.

Another key point of Kodgen is that it is simple to insert and mix custom generated code to the reflection generated code. The Refureku code generator is a simple module added to the Kodgen generator. Users can create and add up as many code generation modules as they want to Kodgen, allowing custom generated code injection to the whole codebase without changing a single line of code in the target program.

Examples

All features in a single header file

#include <Refureku/Refureku.h>

Reflect a class

//TestClass.h
#pragma once

#include "Generated/TestClass.rfkh.h"

class CLASS() TestClass
{
    FIELD()
    int _intField;

    METHOD()
    void testMethod();

    TestClass_GENERATED
};

File_TestClass_GENERATED
//TestClass.cpp, or any source file being part of your project
#include "Generated/TestClass.rfks.h"

Get a class metadata

//From name
rfk::Class const* c = rfk::getDatabase().getFileLevelClassByName("TestClass");

//From static type
rfk::Class const& c2 = TestClass::staticGetArchetype();

//From reflected/unreflected type
rfk::Archetype const* c3 = rfk::getArchetype<TestClass>(); //nullptr if not reflected

Get class metadata from base pointer

This feature is only available to classes that publicly derive from rfk::Object (#include <Refureku/Object.h>).

TestClass instance;
rfk::Object const* instancePtr = &instance;

rfk::Class const& archetype = instancePtr->getArchetype();

Manipulate fields

//Get field
rfk::Field const* field = TestClass::staticGetArchetype().getFieldByName("_intField");

TestClass instance;

//Read field value
int value = field->get<int>(instance);

//Write field value
field->set(instance, 3);

Manipulate methods

//Get method
rfk::Method const* method = TestClass::staticGetArchetype().getMethodByName("testMethod");

TestClass instance;

//Call method without arguments
method->invoke(instance);

//With arguments and returned value
int returnedValue = method->invoke<int>(instance, 1, 2, 3);

Instantiate a class

rfk::Class const* c = rfk::getDatabase().getFileLevelClassByName("TestClass");

//Instantiate from default ctor
rfk::SharedPtr<TestClass> instance = c->makeSharedInstance<TestClass>();

//If TestClass has a base class, we can do
rfk::SharedPtr<BaseClass> instance2 = c->makeSharedInstance<BaseClass>();

It is also possible to instantiate a class with parameters, by providing a custom instantiator when declaring the class:

//TestClass2.h
#pragma once

#include <Refureku/Properties/Instantiator.h>

#include "Generated/TestClass2.rfkh.h"

class CLASS() TestClass2 : public BaseClass
{
    METHOD(rfk::Instantiator)
    static rfk::SharedPtr<TestClass2> customInstantiator(int i)
    {
        //Use this if you don't need custom deleter
        //return rfk::makeShared<TestClass2>();

        //Use this if you want to provide a custom deleter
        return rfk::SharedPtr<TestClass2>(new TestClass2(), [](TestClass2* ptr)
                {
                    delete ptr; //Simple delete for example simplicity
                });
    }

    TestClass2_GENERATED
};

File_TestClass2_GENERATED
//TestClass2.cpp
#include "Generated/TestClass2.rfks.h"
rfk::Class const* c2 = rfk::getDatabase().getFileLevelClassByName("TestClass2");

//Call customInstantiator
rfk::SharedPtr<BaseClass> instance3 = c2->makeSharedInstance<BaseClass>(42);

Create custom properties

//ExampleProperty.h
#pragma once

#include <Refureku/Properties/PropertySettings.h>

#include "Generated/ExampleProperty.rfkh.h"

class CLASS(rfk::PropertySettings(rfk::EEntityKind::Struct | rfk::EEntityKind::Class))
    ExampleProperty : public rfk::Property
{
    public:
        int someData;

        ExampleProperty(int data):
            someData{data}
        {}

    ExampleProperty_GENERATED
};

File_ExampleProperty_GENERATED
//ExampleProperty.cpp, or any source file being part of your project
#include "Generated/ExampleProperty.rfks.h"

Then, we can attach ExampleProperty to any reflected struct or class, as specified by the first argument of PropertySettings. Attaching the property to any other entity will trigger a compilation error with an explicit error message.

//TestClass3.h
#pragma once

#include "ExampleProperty.h" //Include the custom property first
#include "Generated/TestClass3.rfkh.h"

class CLASS(ExampleProperty(42)) TestClass3
{
    TestClass3_GENERATED
};

File_TestClass3_GENERATED
//TestClass3.cpp
#include "Generated/TestClass3.rfks.h"

Read entity properties

rfk::Class const* c = rfk::getDatabase().getFileLevelClassByName("TestClass3");

//From name
rfk::Property const* prop = c->getPropertyByName("ExampleProperty");

//From static type
ExampleProperty const* prop2 = c->getProperty<ExampleProperty>();

Cross-platform compatibility

This library has been tested and is stable on the following configurations:

Known issues