Skip to content

Commit

Permalink
feat(data): Allow wrapped fields to be read as normal object with a s…
Browse files Browse the repository at this point in the history
…ingle field
  • Loading branch information
SrGesus committed Jan 25, 2025
1 parent 395ff0d commit f5c63a5
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 26 deletions.
1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ set(CUBOS_CORE_SOURCE
"src/reflection/traits/enum.cpp"
"src/reflection/traits/mask.cpp"
"src/reflection/traits/inherits.cpp"
"src/reflection/traits/wrapper.cpp"
"src/reflection/external/primitives.cpp"
"src/reflection/external/cstring.cpp"
"src/reflection/external/string.cpp"
Expand Down
15 changes: 14 additions & 1 deletion core/include/cubos/core/ecs/reflection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <cubos/core/reflection/traits/constructible.hpp>
#include <cubos/core/reflection/traits/fields.hpp>
#include <cubos/core/reflection/traits/wrapper.hpp>
#include <cubos/core/reflection/type.hpp>

namespace cubos::core::ecs
Expand Down Expand Up @@ -88,7 +89,7 @@ namespace cubos::core::ecs
/// @param pointer Field pointer.
/// @return Builder.
template <typename F>
TypeBuilder&& withField(std::string name, F T::*pointer) &&
TypeBuilder&& withField(std::string name, F T::* pointer) &&
{
mFields.addField(std::move(name), pointer);
return std::move(*this);
Expand All @@ -102,6 +103,18 @@ namespace cubos::core::ecs
return mType;
}

/// @brief Creates a type with a single field.
/// @tparam F Field type.
/// @param pointer Field pointer.
/// @return Type.
template <typename F>
reflection::Type& wrap(F T::* pointer) &&
{
CUBOS_ASSERT(mFields.size() == 0);
mType.with(reflection::WrapperTrait(pointer));
return mType;
}

private:
reflection::Type& mType;
reflection::FieldsTrait mFields;
Expand Down
55 changes: 55 additions & 0 deletions core/include/cubos/core/reflection/traits/wrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/// @file
/// @brief Class @ref cubos::core::reflection::WrapperTrait.
/// @ingroup core-reflection

#pragma once

#include <cstdint>
#include <string>

#include <cubos/core/reflection/reflect.hpp>
#include <cubos/core/reflection/traits/fields.hpp>
#include <cubos/core/reflection/type.hpp>

namespace cubos::core::reflection
{
/// @brief Describes the single field of a reflected type.
/// @ingroup core-reflection
class CUBOS_CORE_API WrapperTrait
{
public:
CUBOS_REFLECT;

~WrapperTrait()
{
delete mAddressOf;
};

/// @brief Constructs.
template <typename F, typename O>
WrapperTrait(F O::* pointer)
: mType(reflect<F>())
, mAddressOf(new FieldsTrait::AddressOfImpl<O, F>(pointer))
{
}

/// @brief Gets the type of the single field.
/// @return Type.
const Type& type() const
{
return mType;
}

/// @brief Gets a pointer to the field on a given instance of the reflected type.
/// @param instance Pointer to the instance.
/// @return Pointer to the field on the given instance.
void* value(const void* instance) const
{
return reinterpret_cast<void*>(this->mAddressOf->get(instance));
}

private:
const Type& mType;
const FieldsTrait::AddressOf* mAddressOf;
};
} // namespace cubos::core::reflection
20 changes: 8 additions & 12 deletions core/src/data/des/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <cubos/core/reflection/traits/fields.hpp>
#include <cubos/core/reflection/traits/nullable.hpp>
#include <cubos/core/reflection/traits/string_conversion.hpp>
#include <cubos/core/reflection/traits/wrapper.hpp>
#include <cubos/core/reflection/type.hpp>
#include <cubos/core/tel/logging.hpp>

Expand All @@ -23,6 +24,7 @@ using cubos::core::reflection::FieldsTrait;
using cubos::core::reflection::NullableTrait;
using cubos::core::reflection::StringConversionTrait;
using cubos::core::reflection::Type;
using cubos::core::reflection::WrapperTrait;

// NOLINTBEGIN(bugprone-macro-parentheses)
#define AUTO_HOOK(T, fromString) \
Expand Down Expand Up @@ -120,6 +122,12 @@ bool JSONDeserializer::decompose(const Type& type, void* value)
return true;
}

if (type.has<WrapperTrait>())
{
const auto& wrapper = type.get<WrapperTrait>();
return this->read(wrapper.type(), wrapper.value(value));
}

if (type.has<NullableTrait>() && mIterator->is_null())
{
const auto& trait = type.get<NullableTrait>();
Expand Down Expand Up @@ -242,18 +250,6 @@ bool JSONDeserializer::decompose(const Type& type, void* value)
const auto& trait = type.get<FieldsTrait>();
auto view = trait.view(value);

if (trait.size() == 1)
{
// If there's a single field, read it directly.
if (!this->read(trait.begin()->type(), view.begin()->value))
{
CUBOS_WARN("Couldn't deserialize wrapped field {}", trait.begin()->name());
return false;
}

return true;
}

if (!mIterator->is_object())
{
CUBOS_WARN("Expected an object of type {}, found a {}", type.name(), mIterator->type_name());
Expand Down
24 changes: 11 additions & 13 deletions core/src/data/ser/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <cubos/core/reflection/traits/fields.hpp>
#include <cubos/core/reflection/traits/nullable.hpp>
#include <cubos/core/reflection/traits/string_conversion.hpp>
#include <cubos/core/reflection/traits/wrapper.hpp>
#include <cubos/core/reflection/type.hpp>
#include <cubos/core/tel/logging.hpp>

Expand All @@ -19,6 +20,7 @@ using cubos::core::reflection::NullableTrait;
using cubos::core::reflection::reflect;
using cubos::core::reflection::StringConversionTrait;
using cubos::core::reflection::Type;
using cubos::core::reflection::WrapperTrait;

// Macro used to reduce code duplication for primitive type hooks.
#define AUTO_HOOK(type, ...) \
Expand Down Expand Up @@ -65,6 +67,12 @@ nlohmann::json JSONSerializer::output()

bool JSONSerializer::decompose(const Type& type, const void* value)
{
if (type.has<WrapperTrait>())
{
const auto& wrapper = type.get<WrapperTrait>();
return this->write(wrapper.type(), wrapper.value(value));
}

if (type.has<NullableTrait>())
{
const auto& trait = type.get<NullableTrait>();
Expand Down Expand Up @@ -112,21 +120,11 @@ bool JSONSerializer::decompose(const Type& type, const void* value)

if (type.has<FieldsTrait>())
{
if (type.get<FieldsTrait>().size() == 1)
{
// If there's a single field, write it directly.
if (!this->write(type.get<FieldsTrait>().begin()->type(),
type.get<FieldsTrait>().view(value).begin()->value))
{
CUBOS_WARN("Couldn't serialize wrapped field {}", type.get<FieldsTrait>().begin()->name());
return false;
}

return true;
}
const auto& trait = type.get<FieldsTrait>();
auto view = trait.view(value);
auto jsonObj = nlohmann::json::object();

for (const auto& [field, fieldValue] : type.get<FieldsTrait>().view(value))
for (const auto& [field, fieldValue] : view)
{
if (!this->write(field->type(), fieldValue))
{
Expand Down
11 changes: 11 additions & 0 deletions core/src/reflection/traits/wrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <cubos/core/reflection/external/string.hpp>
#include <cubos/core/reflection/traits/wrapper.hpp>
#include <cubos/core/reflection/type.hpp>
#include <cubos/core/tel/logging.hpp>

using namespace cubos::core::reflection;

CUBOS_REFLECT_IMPL(WrapperTrait)
{
return Type::create("cubos::core::ecs::WrapperTrait");
}

0 comments on commit f5c63a5

Please sign in to comment.