diff --git a/include/rfl/internal/all_fields.hpp b/include/rfl/internal/all_fields.hpp index 9d9190b1..4e63b0f3 100644 --- a/include/rfl/internal/all_fields.hpp +++ b/include/rfl/internal/all_fields.hpp @@ -1,23 +1,13 @@ #ifndef RFL_INTERNAL_ALLFIELDS_HPP_ #define RFL_INTERNAL_ALLFIELDS_HPP_ -#include "../Tuple.hpp" #include "is_field.hpp" -namespace rfl { -namespace internal { +namespace rfl::internal { -template -constexpr bool all_fields() { - if constexpr (_i == rfl::tuple_size_v) { - return true; - } else { - using T = tuple_element_t<_i, TupleType>; - return is_field_v && all_fields(); - } -} +template +constexpr bool all_fields_v = (is_field_v && ...); -} // namespace internal -} // namespace rfl +} // namespace rfl::internal #endif diff --git a/include/rfl/internal/is_field.hpp b/include/rfl/internal/is_field.hpp index 4a210814..e8f1b815 100644 --- a/include/rfl/internal/is_field.hpp +++ b/include/rfl/internal/is_field.hpp @@ -6,8 +6,7 @@ #include "../Field.hpp" #include "StringLiteral.hpp" -namespace rfl { -namespace internal { +namespace rfl::internal { template class is_field; @@ -22,7 +21,6 @@ template constexpr bool is_field_v = is_field>>::value; -} // namespace internal -} // namespace rfl +} // namespace rfl::internal #endif diff --git a/include/rfl/parsing/FieldVariantParser.hpp b/include/rfl/parsing/FieldVariantParser.hpp index 8b68f68d..ea455695 100644 --- a/include/rfl/parsing/FieldVariantParser.hpp +++ b/include/rfl/parsing/FieldVariantParser.hpp @@ -5,17 +5,18 @@ #include #include +#include "../NamedTuple.hpp" #include "../Result.hpp" #include "../Tuple.hpp" #include "../Variant.hpp" -#include "../always_false.hpp" -#include "../visit.hpp" +#include "../internal/no_duplicate_field_names.hpp" +#include "../internal/to_ptr_field.hpp" +#include "../make_named_tuple.hpp" #include "FieldVariantReader.hpp" #include "Parser_base.hpp" #include "schema/Type.hpp" -namespace rfl { -namespace parsing { +namespace rfl::parsing { /// To be used when all options of the variants are rfl::Field. Essentially, /// this is an externally tagged union. @@ -93,13 +94,21 @@ struct FieldVariantParser { * @return The schema type. */ static schema::Type to_schema( - std::map* _definitions, - std::vector = {}) { - using VariantType = rfl::Variant...>; - return Parser::to_schema(_definitions); + std::map* _definitions) { + return schema::Type{schema::Type::AnyOf{ + .types_ = std::vector( + {one_field_to_type(_definitions)...})}}; + } + + private: + template + static schema::Type one_field_to_type( + std::map* _definitions) noexcept { + using NamedTupleType = NamedTuple>; + return Parser::to_schema( + _definitions); } }; -} // namespace parsing -} // namespace rfl +} // namespace rfl::parsing #endif diff --git a/include/rfl/parsing/ParserRflVariant.hpp b/include/rfl/parsing/ParserRflVariant.hpp index 744764ff..3b90b173 100644 --- a/include/rfl/parsing/ParserRflVariant.hpp +++ b/include/rfl/parsing/ParserRflVariant.hpp @@ -6,10 +6,10 @@ #include "../Result.hpp" #include "../Variant.hpp" -#include "../always_false.hpp" #include "../internal/add_tags_to_variants_v.hpp" #include "../internal/all_fields.hpp" #include "../internal/nth_element_t.hpp" +#include "../visit.hpp" #include "FieldVariantParser.hpp" #include "Parent.hpp" #include "Parser_base.hpp" @@ -52,7 +52,7 @@ class ParserRflVariant, */ static Result> read( const R& _r, const InputVarType& _var) noexcept { - if constexpr (internal::all_fields>()) { + if constexpr (internal::all_fields_v) { if constexpr (schemaful::IsSchemafulReader) { using WrappedType = rfl::Variant...>; return Parser::read(_r, _var) @@ -124,7 +124,7 @@ class ParserRflVariant, static void write(const W& _w, const rfl::Variant& _variant, const P& _parent) { - if constexpr (internal::all_fields>()) { + if constexpr (internal::all_fields_v) { if constexpr (schemaful::IsSchemafulWriter) { using WrappedType = rfl::Variant< NamedTuple, */ static schema::Type to_schema( std::map* _definitions) { - if constexpr (internal::all_fields>()) { + if constexpr (internal::all_fields_v) { return FieldVariantParser::to_schema(_definitions); @@ -201,29 +201,18 @@ class ParserRflVariant, _definitions); } else { - std::vector types; - build_schema( - _definitions, &types, - std::make_integer_sequence()); - return schema::Type{schema::Type::AnyOf{.types_ = std::move(types)}}; + return schema::Type{schema::Type::AnyOf{ + .types_ = std::vector( + {one_field_to_type(_definitions)...})}}; } } private: - template - static void add_to_schema(std::map* _definitions, - std::vector* _types) noexcept { - using AltType = - std::remove_cvref_t>; - _types->push_back( - Parser::to_schema(_definitions)); - } - - template - static void build_schema(std::map* _definitions, - std::vector* _types, - std::integer_sequence) noexcept { - (add_to_schema<_is>(_definitions, _types), ...); + template + static schema::Type one_field_to_type( + std::map* _definitions) noexcept { + return Parser, + ProcessorsType>::to_schema(_definitions); } template diff --git a/include/rfl/parsing/ParserVariant.hpp b/include/rfl/parsing/ParserVariant.hpp index 61eff403..0fe1e707 100644 --- a/include/rfl/parsing/ParserVariant.hpp +++ b/include/rfl/parsing/ParserVariant.hpp @@ -7,13 +7,12 @@ #include #include "../NamedTuple.hpp" -#include "../Ref.hpp" #include "../Result.hpp" #include "../Variant.hpp" -#include "../always_false.hpp" #include "../internal/add_tags_to_variants_v.hpp" #include "../internal/all_fields.hpp" #include "../internal/to_ptr_field.hpp" +#include "../visit.hpp" #include "FieldVariantParser.hpp" #include "Parent.hpp" #include "Parser_base.hpp" @@ -66,7 +65,7 @@ class ParserVariant, ProcessorsType> { */ static Result> read( const R& _r, const InputVarType& _var) noexcept { - if constexpr (internal::all_fields>()) { + if constexpr (internal::all_fields_v) { if constexpr (schemaful::IsSchemafulReader) { using WrappedType = rfl::Variant...>; return Parser::read(_r, _var) @@ -146,7 +145,7 @@ class ParserVariant, ProcessorsType> { static void write(const W& _w, const std::variant& _variant, const P& _parent) { - if constexpr (internal::all_fields>()) { + if constexpr (internal::all_fields_v) { if constexpr (schemaful::IsSchemafulWriter) { using WrappedType = rfl::Variant< NamedTuple, ProcessorsType> { */ static schema::Type to_schema( std::map* _definitions) { - if constexpr (internal::all_fields>()) { + if constexpr (internal::all_fields_v) { return FieldVariantParser::to_schema(_definitions); @@ -235,42 +234,18 @@ class ParserVariant, ProcessorsType> { _definitions); } else { - std::vector types; - build_schema( - _definitions, &types, - std::make_integer_sequence()); - return schema::Type{schema::Type::AnyOf{.types_ = std::move(types)}}; + return schema::Type{schema::Type::AnyOf{ + .types_ = std::vector( + {one_field_to_type(_definitions)...})}}; } } private: - /** - * @brief Adds an alternative to the schema. - * - * @tparam _i The index of the alternative. - * @param _definitions The map of definitions to add the schema to. - * @param _types The vector of types to add the generated schema to. - */ - template - static void add_to_schema(std::map* _definitions, - std::vector* _types) noexcept { - using U = std::remove_cvref_t< - std::variant_alternative_t<_i, std::variant>>; - _types->push_back(Parser::to_schema(_definitions)); - } - - /** - * @brief Builds the schema for the variant. - * - * @tparam _is The indices of the alternatives. - * @param _definitions The map of definitions to add the schema to. - * @param _types The vector of types to add the generated schemas to. - */ - template - static void build_schema(std::map* _definitions, - std::vector* _types, - std::integer_sequence) noexcept { - (add_to_schema<_is>(_definitions, _types), ...); + template + static schema::Type one_field_to_type( + std::map* _definitions) noexcept { + return Parser, + ProcessorsType>::to_schema(_definitions); } /** diff --git a/tests/json/test_json_schema7.cpp b/tests/json/test_json_schema7.cpp new file mode 100644 index 00000000..f75443ea --- /dev/null +++ b/tests/json/test_json_schema7.cpp @@ -0,0 +1,26 @@ +#include +#include + +namespace test_json_schema7 { + +struct Circle { + double radius; +}; +struct Rectangle { + double height; + double width; +}; + +using Shapes = rfl::Variant; + +TEST(json, test_json_schema7) { + const Shapes r = Rectangle{.height = 10, .width = 5}; + + const auto json_schema = + rfl::json::to_schema(); + + ASSERT_EQ( + json_schema, + R"({"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"type":"object","properties":{"Circle":{"$ref":"#/$defs/test_json_schema7__Circle"}},"required":["Circle"]},{"type":"object","properties":{"Rectangle":{"$ref":"#/$defs/test_json_schema7__Rectangle"}},"required":["Rectangle"]}],"$defs":{"test_json_schema7__Circle":{"type":"object","properties":{"radius":{"type":"number"}},"required":["radius"]},"test_json_schema7__Rectangle":{"type":"object","properties":{"height":{"type":"number"},"width":{"type":"number"}},"required":["height","width"]}}})"); +} +} // namespace test_json_schema7