Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 4 additions & 14 deletions include/rfl/internal/all_fields.hpp
Original file line number Diff line number Diff line change
@@ -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 <class TupleType, int _i = 0>
constexpr bool all_fields() {
if constexpr (_i == rfl::tuple_size_v<TupleType>) {
return true;
} else {
using T = tuple_element_t<_i, TupleType>;
return is_field_v<T> && all_fields<TupleType, _i + 1>();
}
}
template <class... Ts>
constexpr bool all_fields_v = (is_field_v<Ts> && ...);

} // namespace internal
} // namespace rfl
} // namespace rfl::internal

#endif
6 changes: 2 additions & 4 deletions include/rfl/internal/is_field.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
#include "../Field.hpp"
#include "StringLiteral.hpp"

namespace rfl {
namespace internal {
namespace rfl::internal {

template <class T>
class is_field;
Expand All @@ -22,7 +21,6 @@ template <class T>
constexpr bool is_field_v =
is_field<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;

} // namespace internal
} // namespace rfl
} // namespace rfl::internal

#endif
29 changes: 19 additions & 10 deletions include/rfl/parsing/FieldVariantParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@
#include <string>
#include <type_traits>

#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.
Expand Down Expand Up @@ -93,13 +94,21 @@ struct FieldVariantParser {
* @return The schema type.
*/
static schema::Type to_schema(
std::map<std::string, schema::Type>* _definitions,
std::vector<schema::Type> = {}) {
using VariantType = rfl::Variant<NamedTuple<FieldTypes>...>;
return Parser<R, W, VariantType, ProcessorsType>::to_schema(_definitions);
std::map<std::string, schema::Type>* _definitions) {
return schema::Type{schema::Type::AnyOf{
.types_ = std::vector<schema::Type>(
{one_field_to_type<FieldTypes>(_definitions)...})}};
}

private:
template <class FieldType>
static schema::Type one_field_to_type(
std::map<std::string, schema::Type>* _definitions) noexcept {
using NamedTupleType = NamedTuple<std::remove_cvref_t<FieldType>>;
return Parser<R, W, NamedTupleType, ProcessorsType>::to_schema(
_definitions);
}
};
} // namespace parsing
} // namespace rfl
} // namespace rfl::parsing

#endif
35 changes: 12 additions & 23 deletions include/rfl/parsing/ParserRflVariant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -52,7 +52,7 @@ class ParserRflVariant<R, W, rfl::Variant<AlternativeTypes...>,
*/
static Result<rfl::Variant<AlternativeTypes...>> read(
const R& _r, const InputVarType& _var) noexcept {
if constexpr (internal::all_fields<std::tuple<AlternativeTypes...>>()) {
if constexpr (internal::all_fields_v<AlternativeTypes...>) {
if constexpr (schemaful::IsSchemafulReader<R>) {
using WrappedType = rfl::Variant<NamedTuple<AlternativeTypes>...>;
return Parser<R, W, WrappedType, ProcessorsType>::read(_r, _var)
Expand Down Expand Up @@ -124,7 +124,7 @@ class ParserRflVariant<R, W, rfl::Variant<AlternativeTypes...>,
static void write(const W& _w,
const rfl::Variant<AlternativeTypes...>& _variant,
const P& _parent) {
if constexpr (internal::all_fields<std::tuple<AlternativeTypes...>>()) {
if constexpr (internal::all_fields_v<AlternativeTypes...>) {
if constexpr (schemaful::IsSchemafulWriter<W>) {
using WrappedType = rfl::Variant<
NamedTuple<Field<AlternativeTypes::name_,
Expand Down Expand Up @@ -186,7 +186,7 @@ class ParserRflVariant<R, W, rfl::Variant<AlternativeTypes...>,
*/
static schema::Type to_schema(
std::map<std::string, schema::Type>* _definitions) {
if constexpr (internal::all_fields<std::tuple<AlternativeTypes...>>()) {
if constexpr (internal::all_fields_v<AlternativeTypes...>) {
return FieldVariantParser<R, W, ProcessorsType,
AlternativeTypes...>::to_schema(_definitions);

Expand All @@ -201,29 +201,18 @@ class ParserRflVariant<R, W, rfl::Variant<AlternativeTypes...>,
_definitions);

} else {
std::vector<schema::Type> types;
build_schema(
_definitions, &types,
std::make_integer_sequence<int, sizeof...(AlternativeTypes)>());
return schema::Type{schema::Type::AnyOf{.types_ = std::move(types)}};
return schema::Type{schema::Type::AnyOf{
.types_ = std::vector<schema::Type>(
{one_field_to_type<AlternativeTypes>(_definitions)...})}};
}
}

private:
template <size_t _i>
static void add_to_schema(std::map<std::string, schema::Type>* _definitions,
std::vector<schema::Type>* _types) noexcept {
using AltType =
std::remove_cvref_t<internal::nth_element_t<_i, AlternativeTypes...>>;
_types->push_back(
Parser<R, W, AltType, ProcessorsType>::to_schema(_definitions));
}

template <int... _is>
static void build_schema(std::map<std::string, schema::Type>* _definitions,
std::vector<schema::Type>* _types,
std::integer_sequence<int, _is...>) noexcept {
(add_to_schema<_is>(_definitions, _types), ...);
template <class AltType>
static schema::Type one_field_to_type(
std::map<std::string, schema::Type>* _definitions) noexcept {
return Parser<R, W, std::remove_cvref_t<AltType>,
ProcessorsType>::to_schema(_definitions);
}

template <int _i>
Expand Down
49 changes: 12 additions & 37 deletions include/rfl/parsing/ParserVariant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
#include <variant>

#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"
Expand Down Expand Up @@ -66,7 +65,7 @@ class ParserVariant<R, W, std::variant<AlternativeTypes...>, ProcessorsType> {
*/
static Result<std::variant<AlternativeTypes...>> read(
const R& _r, const InputVarType& _var) noexcept {
if constexpr (internal::all_fields<std::tuple<AlternativeTypes...>>()) {
if constexpr (internal::all_fields_v<AlternativeTypes...>) {
if constexpr (schemaful::IsSchemafulReader<R>) {
using WrappedType = rfl::Variant<NamedTuple<AlternativeTypes>...>;
return Parser<R, W, WrappedType, ProcessorsType>::read(_r, _var)
Expand Down Expand Up @@ -146,7 +145,7 @@ class ParserVariant<R, W, std::variant<AlternativeTypes...>, ProcessorsType> {
static void write(const W& _w,
const std::variant<AlternativeTypes...>& _variant,
const P& _parent) {
if constexpr (internal::all_fields<std::tuple<AlternativeTypes...>>()) {
if constexpr (internal::all_fields_v<AlternativeTypes...>) {
if constexpr (schemaful::IsSchemafulWriter<W>) {
using WrappedType = rfl::Variant<
NamedTuple<Field<AlternativeTypes::name_,
Expand Down Expand Up @@ -220,7 +219,7 @@ class ParserVariant<R, W, std::variant<AlternativeTypes...>, ProcessorsType> {
*/
static schema::Type to_schema(
std::map<std::string, schema::Type>* _definitions) {
if constexpr (internal::all_fields<std::tuple<AlternativeTypes...>>()) {
if constexpr (internal::all_fields_v<AlternativeTypes...>) {
return FieldVariantParser<R, W, ProcessorsType,
AlternativeTypes...>::to_schema(_definitions);

Expand All @@ -235,42 +234,18 @@ class ParserVariant<R, W, std::variant<AlternativeTypes...>, ProcessorsType> {
_definitions);

} else {
std::vector<schema::Type> types;
build_schema(
_definitions, &types,
std::make_integer_sequence<int, sizeof...(AlternativeTypes)>());
return schema::Type{schema::Type::AnyOf{.types_ = std::move(types)}};
return schema::Type{schema::Type::AnyOf{
.types_ = std::vector<schema::Type>(
{one_field_to_type<AlternativeTypes>(_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 <size_t _i>
static void add_to_schema(std::map<std::string, schema::Type>* _definitions,
std::vector<schema::Type>* _types) noexcept {
using U = std::remove_cvref_t<
std::variant_alternative_t<_i, std::variant<AlternativeTypes...>>>;
_types->push_back(Parser<R, W, U, ProcessorsType>::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 <int... _is>
static void build_schema(std::map<std::string, schema::Type>* _definitions,
std::vector<schema::Type>* _types,
std::integer_sequence<int, _is...>) noexcept {
(add_to_schema<_is>(_definitions, _types), ...);
template <class AltType>
static schema::Type one_field_to_type(
std::map<std::string, schema::Type>* _definitions) noexcept {
return Parser<R, W, std::remove_cvref_t<AltType>,
ProcessorsType>::to_schema(_definitions);
}

/**
Expand Down
26 changes: 26 additions & 0 deletions tests/json/test_json_schema7.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <rfl.hpp>
#include <rfl/json.hpp>

namespace test_json_schema7 {

struct Circle {
double radius;
};
struct Rectangle {
double height;
double width;
};

using Shapes = rfl::Variant<Circle, Rectangle>;

TEST(json, test_json_schema7) {
const Shapes r = Rectangle{.height = 10, .width = 5};

const auto json_schema =
rfl::json::to_schema<Shapes, rfl::AddTagsToVariants>();

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
Loading