diff --git a/include/rfl/parsing/Parser_enum.hpp b/include/rfl/parsing/Parser_enum.hpp index 283b94ba..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" @@ -29,7 +30,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 +58,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 +74,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 +99,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 diff --git a/tests/json/test_custom_enum1.cpp b/tests/json/test_custom_enum1.cpp new file mode 100644 index 00000000..7c4509d5 --- /dev/null +++ b/tests/json/test_custom_enum1.cpp @@ -0,0 +1,60 @@ +#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 diff --git a/tests/json/test_json_schema6.cpp b/tests/json/test_json_schema6.cpp new file mode 100644 index 00000000..df516f0c --- /dev/null +++ b/tests/json/test_json_schema6.cpp @@ -0,0 +1,60 @@ +#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