From 702e6da1bec8640723baabd1cc71fe8915f3febd Mon Sep 17 00:00:00 2001 From: FrancescoMerenda Date: Tue, 3 Feb 2026 21:17:41 +0100 Subject: [PATCH 1/6] fix: allows usage of stateful visitors inside rfl::Variant --- include/rfl/Variant.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/rfl/Variant.hpp b/include/rfl/Variant.hpp index 855a0462..6b92f947 100644 --- a/include/rfl/Variant.hpp +++ b/include/rfl/Variant.hpp @@ -223,7 +223,7 @@ class Variant { template void do_visit_no_result(F& _f, bool* _visited, std::integer_sequence) { - auto visit_one = [this](const F& _f, bool* _visited, + auto visit_one = [this](F& _f, bool* _visited, Index<_i>) { if (!*_visited && index_ == _i) { _f(get_alternative<_i>()); @@ -236,7 +236,7 @@ class Variant { template void do_visit_no_result(F& _f, bool* _visited, std::integer_sequence) const { - auto visit_one = [this](const F& _f, bool* _visited, + auto visit_one = [this](F& _f, bool* _visited, Index<_i>) { if (!*_visited && index_ == _i) { _f(get_alternative<_i>()); @@ -275,7 +275,7 @@ class Variant { template void do_visit_with_result(F& _f, std::optional* _result, std::integer_sequence) { - auto visit_one = [this](const F& _f, + auto visit_one = [this](F& _f, std::optional* _result, Index<_i>) { if (!*_result && index_ == _i) { @@ -288,7 +288,7 @@ class Variant { template void do_visit_with_result(F& _f, std::optional* _result, std::integer_sequence) const { - auto visit_one = [this](const F& _f, + auto visit_one = [this](F& _f, std::optional* _result, Index<_i>) { if (!*_result && index_ == _i) { @@ -328,7 +328,7 @@ class Variant { void do_visit_with_reference(F& _f, ResultType** _result, std::integer_sequence) { const auto visit_one = [this]( - const F& _f, ResultType** _result, Index<_i>) { + F& _f, ResultType** _result, Index<_i>) { if (!*_result && index_ == _i) { *_result = &_f(get_alternative<_i>()); } @@ -340,7 +340,7 @@ class Variant { void do_visit_with_reference(F& _f, ResultType** _result, std::integer_sequence) const { const auto visit_one = [this]( - const F& _f, ResultType** _result, Index<_i>) { + F& _f, ResultType** _result, Index<_i>) { if (!*_result && index_ == _i) { *_result = &_f(get_alternative<_i>()); } From d968534bbdf0d4f09d76eedac42784b17cac4e38 Mon Sep 17 00:00:00 2001 From: FrancescoMerenda Date: Mon, 23 Feb 2026 22:54:58 +0100 Subject: [PATCH 2/6] fix: allows definition of custom reflectors for enum types --- include/rfl/parsing/Parser_enum.hpp | 40 ++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/include/rfl/parsing/Parser_enum.hpp b/include/rfl/parsing/Parser_enum.hpp index 283b94ba..9a02f7df 100644 --- a/include/rfl/parsing/Parser_enum.hpp +++ b/include/rfl/parsing/Parser_enum.hpp @@ -29,7 +29,20 @@ struct Parser { /// Expresses the variables as type T. static Result read(const R& _r, const InputVarType& _var) noexcept { - if constexpr (ProcessorsType::underlying_enums_ || + if constexpr (internal::has_read_reflector) { + const auto wrap_in_t = [](auto&& _named_tuple) -> Result { + try { + using NT = decltype(_named_tuple); + return Reflector::to(std::forward(_named_tuple)); + } catch (std::exception& e) { + return error(e.what()); + } + }; + return Parser::ReflType, + ProcessorsType>::read(_r, _var) + .and_then(wrap_in_t); + + } else if constexpr (ProcessorsType::underlying_enums_ || schemaful::IsSchemafulReader) { static_assert(enchantum::ScopedEnum, "The enum must be a scoped enum in order to retrieve " @@ -44,7 +57,10 @@ struct Parser { template static void write(const W& _w, const T& _var, const P& _parent) { - if constexpr (ProcessorsType::underlying_enums_ || + if constexpr (internal::has_write_reflector) { + Parser::ReflType, ProcessorsType>::write( + _w, Reflector::from(_var), _parent); + } else if constexpr (ProcessorsType::underlying_enums_ || schemaful::IsSchemafulWriter) { const auto val = static_cast>(_var); ParentType::add_value(_w, val, _parent); @@ -57,7 +73,12 @@ struct Parser { static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; - return make_enum(_definitions); + if constexpr (internal::has_read_reflector || + internal::has_write_reflector) { + return make_reference(_definitions); + } else { + return make_enum(_definitions); + } } private: @@ -77,6 +98,19 @@ struct Parser { ProcessorsType>::to_schema(_definitions); } } + + template + static schema::Type make_reference( + std::map* _definitions) { + using Type = schema::Type; + const auto name = make_type_name(); + + if (_definitions->find(name) == _definitions->end()) { + (*_definitions)[name] = Parser::ReflType, + ProcessorsType>::to_schema(_definitions); + } + return Type{Type::Reference{name}}; + } }; } // namespace rfl::parsing From 89d4e84f8eb7d2bd6a1dab49807a2a4dec996c8c Mon Sep 17 00:00:00 2001 From: FrancescoMerenda Date: Mon, 23 Feb 2026 22:55:36 +0100 Subject: [PATCH 3/6] added test for serialization and deserialization of enums with custom reflectors --- tests/json/test_custom_enum1.cpp | 61 ++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/json/test_custom_enum1.cpp diff --git a/tests/json/test_custom_enum1.cpp b/tests/json/test_custom_enum1.cpp new file mode 100644 index 00000000..fc1dc306 --- /dev/null +++ b/tests/json/test_custom_enum1.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +#include "write_and_read.hpp" + +namespace test_custom_enum1 { + +enum class Role { + Normal = 0, + Admin = 1, + SuperAdmin = 0xFF, +}; + +struct User { + std::string id; + Role role; + std::string username; +}; + +} // namespace test_custom_enum1 + + +namespace rfl { +template <> +struct Reflector { + using ReflType = uint32_t; + + static test_custom_enum1::Role to(const ReflType& v) { + test_custom_enum1::Role rv = static_cast(v); + switch (rv) { + case test_custom_enum1::Role::Normal: + case test_custom_enum1::Role::Admin: + case test_custom_enum1::Role::SuperAdmin: + return rv; + default: + throw "invalid role value"; + } + } + + static ReflType from(const test_custom_enum1::Role& v) { + return static_cast(v); + } +}; +}; + +namespace test_custom_enum1 { + +TEST(json, test_custom_enum1) { + const auto test1 = test_custom_enum1::User{ + .id = "123", + .role = test_custom_enum1::Role::SuperAdmin, + .username = "bart", + }; + const auto test2 = rfl::json::read( + rfl::json::write(test1)).value(); + + write_and_read(test2, R"({"id":"123","role":255,"username":"bart"})"); +} +} // namespace test_custom_class4 From f0d153a60f90ea9e69e6778b4558b56e6f1196c7 Mon Sep 17 00:00:00 2001 From: FrancescoMerenda Date: Mon, 23 Feb 2026 22:57:45 +0100 Subject: [PATCH 4/6] added test for json schema generation of enum types with custom reflectors --- tests/json/test_json_schema6.cpp | 61 ++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/json/test_json_schema6.cpp diff --git a/tests/json/test_json_schema6.cpp b/tests/json/test_json_schema6.cpp new file mode 100644 index 00000000..545bf8f5 --- /dev/null +++ b/tests/json/test_json_schema6.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +#include "write_and_read.hpp" + + +namespace test_json_schema6 { + +enum class Role { + Normal = 0, + Admin = 1, + SuperAdmin = 0xFF, +}; + +struct User { + std::string id; + Role role; + std::string username; +}; + +} // namespace test_json_schema6 + + +namespace rfl { +template <> +struct Reflector { + using ReflType = uint32_t; + + static test_json_schema6::Role to(const ReflType& v) { + test_json_schema6::Role rv = static_cast(v); + switch (rv) { + case test_json_schema6::Role::Normal: + case test_json_schema6::Role::Admin: + case test_json_schema6::Role::SuperAdmin: + return rv; + default: + throw "invalid role value"; + } + } + + static ReflType from(const test_json_schema6::Role& v) { + return static_cast(v); + } +}; +}; + + + +namespace test_json_schema6 { + +TEST(json, test_json_schema6) { + const auto json_schema = rfl::json::to_schema(); + + const std::string expected = + R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_json_schema6__User","$defs":{"test_json_schema6__Role":{"type":"integer"},"test_json_schema6__User":{"type":"object","properties":{"id":{"type":"string"},"role":{"$ref":"#/$defs/test_json_schema6__Role"},"username":{"type":"string"}},"required":["id","role","username"]}}})"; + + EXPECT_EQ(json_schema, expected); +} +} // namespace test_json_schema6 From fd004fdf06e29d002a60fccf356ff674aa5d511c Mon Sep 17 00:00:00 2001 From: FrancescoMerenda Date: Mon, 23 Feb 2026 23:02:44 +0100 Subject: [PATCH 5/6] removed unused includes --- tests/json/test_custom_enum1.cpp | 1 - tests/json/test_json_schema6.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/json/test_custom_enum1.cpp b/tests/json/test_custom_enum1.cpp index fc1dc306..7c4509d5 100644 --- a/tests/json/test_custom_enum1.cpp +++ b/tests/json/test_custom_enum1.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/tests/json/test_json_schema6.cpp b/tests/json/test_json_schema6.cpp index 545bf8f5..df516f0c 100644 --- a/tests/json/test_json_schema6.cpp +++ b/tests/json/test_json_schema6.cpp @@ -1,4 +1,3 @@ -#include #include #include #include From 331c22db6a8a284683a310e8c9aaa27e2733cf17 Mon Sep 17 00:00:00 2001 From: FrancescoMerenda Date: Tue, 24 Feb 2026 22:06:18 +0100 Subject: [PATCH 6/6] added include --- include/rfl/parsing/Parser_enum.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/rfl/parsing/Parser_enum.hpp b/include/rfl/parsing/Parser_enum.hpp index 9a02f7df..dabf89d0 100644 --- a/include/rfl/parsing/Parser_enum.hpp +++ b/include/rfl/parsing/Parser_enum.hpp @@ -7,6 +7,7 @@ #include "../Result.hpp" #include "../enums.hpp" #include "../thirdparty/enchantum/enchantum.hpp" +#include "../internal/has_reflector.hpp" #include "AreReaderAndWriter.hpp" #include "Parent.hpp" #include "Parser_base.hpp"