From d9501b6424d48d4292a5f79ee4436280cd9c369b Mon Sep 17 00:00:00 2001 From: George Evmenov Date: Wed, 2 Oct 2024 14:32:48 +0300 Subject: [PATCH 1/2] remove duplicate CMake code in REFLECTCPP_USE_BUNDLED_DEPENDENCIES --- CMakeLists.txt | 58 +++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d4a6882..b642c24a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,50 +40,46 @@ project(reflectcpp LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) -if(REFLECTCPP_USE_BUNDLED_DEPENDENCIES) - if (REFLECTCPP_BUILD_SHARED) - add_library(reflectcpp SHARED) - else() - add_library(reflectcpp STATIC) - endif() +if (REFLECTCPP_BUILD_SHARED) + add_library(reflectcpp SHARED) +else() + add_library(reflectcpp STATIC) +endif() - target_sources(reflectcpp PRIVATE src/reflectcpp.cpp src/yyjson.c) - set_source_files_properties(src/yyjson.c PROPERTIES LANGUAGE CXX) +if (MSVC) + target_compile_options(reflectcpp PRIVATE $<$:-Wall>) +else() + target_compile_options(reflectcpp PRIVATE $<$:-Wall -Wextra>) +endif() - target_compile_features(reflectcpp PUBLIC cxx_std_20) +target_compile_features(reflectcpp PUBLIC cxx_std_20) - if (MSVC) - target_compile_options(reflectcpp PRIVATE $<$:-Wall>) - else() - target_compile_options(reflectcpp PRIVATE $<$:-Wall -Wextra>) - endif() +set(REFLECT_CPP_SOURCES + src/reflectcpp.cpp +) - target_include_directories( - reflectcpp PUBLIC - $ - $ - $) -else() - if (REFLECTCPP_BUILD_SHARED) - add_library(reflectcpp SHARED) - else() - add_library(reflectcpp STATIC) - endif() +target_include_directories( + reflectcpp PUBLIC + $ + $) - target_sources(reflectcpp PRIVATE src/reflectcpp.cpp) +if(REFLECTCPP_USE_BUNDLED_DEPENDENCIES) + list(APPEND REFLECT_CPP_SOURCES + src/yyjson.c + ) + set_source_files_properties(src/yyjson.c PROPERTIES LANGUAGE CXX) target_include_directories( reflectcpp PUBLIC - $ - $) - - target_compile_features(reflectcpp PUBLIC cxx_std_20) - + $) +else() find_package(ctre CONFIG REQUIRED) find_package(yyjson CONFIG REQUIRED) target_link_libraries(reflectcpp INTERFACE ctre::ctre yyjson::yyjson) endif() +target_sources(reflectcpp PRIVATE ${REFLECT_CPP_SOURCES}) + set_target_properties(reflectcpp PROPERTIES LINKER_LANGUAGE CXX) if (REFLECTCPP_BSON) From fa287849d79768fa3e491b3fc60ab0a4d6eb974a Mon Sep 17 00:00:00 2001 From: George Evmenov Date: Wed, 2 Oct 2024 14:33:00 +0300 Subject: [PATCH 2/2] split reflectcpp.cpp file into multiple source files, without changing build --- src/Generic.cpp | 114 ++++++++++++++ src/Type.cpp | 40 +++++ src/reflectcpp.cpp | 373 +-------------------------------------------- src/to_schema.cpp | 279 +++++++++++++++++++++++++++++++++ 4 files changed, 441 insertions(+), 365 deletions(-) create mode 100644 src/Generic.cpp create mode 100644 src/Type.cpp create mode 100644 src/to_schema.cpp diff --git a/src/Generic.cpp b/src/Generic.cpp new file mode 100644 index 00000000..cdc78d54 --- /dev/null +++ b/src/Generic.cpp @@ -0,0 +1,114 @@ +/* + +MIT License + +Copyright (c) 2023-2024 Code17 GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "rfl/Generic.hpp" + +namespace rfl { + +Generic::Generic() : value_(false) {} + +Generic::Generic(Generic&& _other) noexcept = default; + +Generic::Generic(const Generic& _other) = default; + +Generic::Generic(const ReflectionType& _value) : value_(_value) {} + +Generic::Generic(ReflectionType&& _value) noexcept + : value_(std::move(_value)) {} + +Generic::~Generic() = default; + +Generic& Generic::operator=(const ReflectionType& _value) { + value_ = _value; + return *this; +} + +Generic& Generic::operator=(ReflectionType&& _value) noexcept { + value_ = std::move(_value); + return *this; +} + +Generic& Generic::operator=(const Generic& _other) = default; + +Generic& Generic::operator=(Generic&& _other) = default; + +Result Generic::to_array() const noexcept { + if (const auto* ptr = std::get_if(&value_)) { + return *ptr; + } else { + return Error( + "rfl::Generic: Could not cast the underlying value to an " + "rfl::Generic::Array."); + } +} + +Result Generic::to_bool() const noexcept { + if (const auto* ptr = std::get_if(&value_)) { + return *ptr; + } else { + return Error( + "rfl::Generic: Could not cast the underlying value to a boolean."); + } +} + +Result Generic::to_double() const noexcept { + if (const auto* ptr = std::get_if(&value_)) { + return *ptr; + } else { + return Error( + "rfl::Generic: Could not cast the underlying value to a double."); + } +} + +Result Generic::to_int() const noexcept { + if (const auto* ptr = std::get_if(&value_)) { + return *ptr; + } else { + return Error( + "rfl::Generic: Could not cast the underlying value to an integer."); + } +} + +Result Generic::to_object() const noexcept { + if (const auto* ptr = std::get_if(&value_)) { + return *ptr; + } else { + return Error( + "rfl::Generic: Could not cast the underlying value to an " + "rfl::Generic::Object."); + } +} + +Result Generic::to_string() const noexcept { + if (const auto* ptr = std::get_if(&value_)) { + return *ptr; + } else { + return Error( + "rfl::Generic: Could not cast the underlying value to a string."); + } +} + +} // namespace rfl diff --git a/src/Type.cpp b/src/Type.cpp new file mode 100644 index 00000000..d05da4ea --- /dev/null +++ b/src/Type.cpp @@ -0,0 +1,40 @@ +/* + +MIT License + +Copyright (c) 2023-2024 Code17 GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "rfl/parsing/schema/Type.hpp" + +namespace rfl::parsing::schema { + +/// Requires a lot of template instantiation, so we do not want this to be +/// inlined. + +Type::Type() : variant_() {} + +Type::Type(const VariantType& _variant) : variant_(_variant) {} + +Type::~Type() = default; + +} // namespace rfl::parsing::schema diff --git a/src/reflectcpp.cpp b/src/reflectcpp.cpp index b6adc401..6071dd43 100644 --- a/src/reflectcpp.cpp +++ b/src/reflectcpp.cpp @@ -24,368 +24,11 @@ SOFTWARE. */ -// ---------------------------------------------------------------------------- - -#include "rfl/Generic.hpp" - -namespace rfl { - -Generic::Generic() : value_(false) {} - -Generic::Generic(Generic&& _other) noexcept = default; - -Generic::Generic(const Generic& _other) = default; - -Generic::Generic(const ReflectionType& _value) : value_(_value) {} - -Generic::Generic(ReflectionType&& _value) noexcept - : value_(std::move(_value)) {} - -Generic::~Generic() = default; - -Generic& Generic::operator=(const ReflectionType& _value) { - value_ = _value; - return *this; -} - -Generic& Generic::operator=(ReflectionType&& _value) noexcept { - value_ = std::move(_value); - return *this; -} - -Generic& Generic::operator=(const Generic& _other) = default; - -Generic& Generic::operator=(Generic&& _other) = default; - -Result Generic::to_array() const noexcept { - if (const auto* ptr = std::get_if(&value_)) { - return *ptr; - } else { - return Error( - "rfl::Generic: Could not cast the underlying value to an " - "rfl::Generic::Array."); - } -} - -Result Generic::to_bool() const noexcept { - if (const auto* ptr = std::get_if(&value_)) { - return *ptr; - } else { - return Error( - "rfl::Generic: Could not cast the underlying value to a boolean."); - } -} - -Result Generic::to_double() const noexcept { - if (const auto* ptr = std::get_if(&value_)) { - return *ptr; - } else { - return Error( - "rfl::Generic: Could not cast the underlying value to a double."); - } -} - -Result Generic::to_int() const noexcept { - if (const auto* ptr = std::get_if(&value_)) { - return *ptr; - } else { - return Error( - "rfl::Generic: Could not cast the underlying value to an integer."); - } -} - -Result Generic::to_object() const noexcept { - if (const auto* ptr = std::get_if(&value_)) { - return *ptr; - } else { - return Error( - "rfl::Generic: Could not cast the underlying value to an " - "rfl::Generic::Object."); - } -} - -Result Generic::to_string() const noexcept { - if (const auto* ptr = std::get_if(&value_)) { - return *ptr; - } else { - return Error( - "rfl::Generic: Could not cast the underlying value to a string."); - } -} - -} // namespace rfl - -// ---------------------------------------------------------------------------- - -#include "rfl/json/to_schema.hpp" - -namespace rfl::json { - -schema::Type type_to_json_schema_type(const parsing::schema::Type& _type); - -bool is_optional(const parsing::schema::Type& _t) { - const auto handle = [](const auto& _v) -> bool { - using T = std::remove_cvref_t; - return std::is_same(); - }; - return rfl::visit(handle, _t.variant_); -} - -std::string numeric_type_to_string(const parsing::schema::Type& _type) { - const auto handle_variant = [](const auto& _t) -> std::string { - using T = std::remove_cvref_t; - using Type = parsing::schema::Type; - if constexpr (std::is_same() || - std::is_same() || - std::is_same() || - std::is_same() || - std::is_same()) { - return schema::Type::Integer{}.type.str(); - } else { - return schema::Type::Number{}.type.str(); - } - }; - return rfl::visit(handle_variant, _type.variant_); -} - -schema::Type handle_validation_type( - const parsing::schema::Type& _type, - const parsing::schema::ValidationType& _validation_type) { - auto handle_variant = [&](const auto& _v) -> schema::Type { - using T = std::remove_cvref_t; - using ValidationType = parsing::schema::ValidationType; - if constexpr (std::is_same()) { - auto all_of = std::vector(); - for (const auto& t : _v.types_) { - all_of.emplace_back(handle_validation_type(_type, t)); - } - return schema::Type{.value = schema::Type::AllOf{.allOf = all_of}}; - - } else if constexpr (std::is_same()) { - auto any_of = std::vector(); - for (const auto& t : _v.types_) { - any_of.emplace_back(handle_validation_type(_type, t)); - } - return schema::Type{.value = schema::Type::AnyOf{.anyOf = any_of}}; - - } else if constexpr (std::is_same()) { - auto one_of = std::vector(); - for (const auto& t : _v.types_) { - one_of.emplace_back(handle_validation_type(_type, t)); - } - return schema::Type{.value = schema::Type::OneOf{.oneOf = one_of}}; - - } else if constexpr (std::is_same()) { - return schema::Type{.value = schema::Type::Regex{.pattern = _v.pattern_}}; - - } else if constexpr (std::is_same()) { - auto t = type_to_json_schema_type(_type); - const auto to_size = [](const auto _v) { - return static_cast(_v); - }; - auto handle_size_variant = [&](auto& _t, const auto& _size_limit) { - using U = std::remove_cvref_t; - using V = std::remove_cvref_t; - if constexpr (std::is_same() || - std::is_same()) { - if constexpr (std::is_same()) { - _t.minSize = _size_limit.value_.visit(to_size); - return t; - - } else if constexpr (std::is_same()) { - _t.maxSize = _size_limit.value_.visit(to_size); - return t; - - } else if constexpr (std::is_same()) { - _t.minSize = _size_limit.value_.visit(to_size); - _t.maxSize = _size_limit.value_.visit(to_size); - return t; - - } else if constexpr (std::is_same() || - std::is_same()) { - V v; - for (const auto& limiter : _size_limit.types_) { - v.types_.push_back(ValidationType{ValidationType::Size{ - .size_limit_ = rfl::Ref::make(limiter)}}); - } - return handle_validation_type(_type, ValidationType{.variant_ = v}); - } - } - return t; - }; - - return rfl::visit(handle_size_variant, t.value, _v.size_limit_->variant_); - - } else if constexpr (std::is_same()) { - return schema::Type{.value = schema::Type::ExclusiveMaximum{ - .exclusiveMaximum = _v.value_, - .type = numeric_type_to_string(_type)}}; - - } else if constexpr (std::is_same()) { - return schema::Type{.value = schema::Type::ExclusiveMinimum{ - .exclusiveMinimum = _v.value_, - .type = numeric_type_to_string(_type)}}; - - } else if constexpr (std::is_same()) { - return schema::Type{ - .value = schema::Type::Maximum{ - .maximum = _v.value_, .type = numeric_type_to_string(_type)}}; - - } else if constexpr (std::is_same()) { - return schema::Type{ - .value = schema::Type::Minimum{ - .minimum = _v.value_, .type = numeric_type_to_string(_type)}}; - - } else if constexpr (std::is_same()) { - const auto maximum = schema::Type{ - .value = schema::Type::Maximum{ - .maximum = _v.value_, .type = numeric_type_to_string(_type)}}; - const auto minimum = schema::Type{ - .value = schema::Type::Minimum{ - .minimum = _v.value_, .type = numeric_type_to_string(_type)}}; - return schema::Type{.value = - schema::Type::AllOf{.allOf = {maximum, minimum}}}; - - } else if constexpr (std::is_same()) { - const auto excl_maximum = - schema::Type{.value = schema::Type::ExclusiveMaximum{ - .exclusiveMaximum = _v.value_, - .type = numeric_type_to_string(_type)}}; - const auto excl_minimum = - schema::Type{.value = schema::Type::ExclusiveMinimum{ - .exclusiveMinimum = _v.value_, - .type = numeric_type_to_string(_type)}}; - return schema::Type{ - .value = schema::Type::AnyOf{.anyOf = {excl_maximum, excl_minimum}}}; - - } else { - static_assert(rfl::always_false_v, "Not all cases were covered."); - } - }; - - return rfl::visit(handle_variant, _validation_type.variant_); -} - -schema::Type type_to_json_schema_type(const parsing::schema::Type& _type) { - auto handle_variant = [](const auto& _t) -> schema::Type { - using T = std::remove_cvref_t; - using Type = parsing::schema::Type; - if constexpr (std::is_same()) { - return schema::Type{.value = schema::Type::Boolean{}}; - - } else if constexpr (std::is_same() || - std::is_same() || - std::is_same() || - std::is_same() || - std::is_same()) { - return schema::Type{.value = schema::Type::Integer{}}; - - } else if constexpr (std::is_same() || - std::is_same()) { - return schema::Type{.value = schema::Type::Number{}}; - - } else if constexpr (std::is_same()) { - return schema::Type{.value = schema::Type::String{}}; - - } else if constexpr (std::is_same()) { - auto any_of = std::vector(); - for (const auto& t : _t.types_) { - any_of.emplace_back(type_to_json_schema_type(t)); - } - return schema::Type{.value = schema::Type::AnyOf{.anyOf = any_of}}; - - } else if constexpr (std::is_same()) { - auto res = type_to_json_schema_type(*_t.type_); - const auto update_prediction = [&](auto _v) -> schema::Type { - _v.description = _t.description_; - return schema::Type{_v}; - }; - return rfl::visit(update_prediction, res.value); - - } else if constexpr (std::is_same()) { - return schema::Type{.value = schema::Type::FixedSizeTypedArray{ - .items = Ref::make( - type_to_json_schema_type(*_t.type_)), - .minItems = _t.size_, - .maxItems = _t.size_}}; - - } else if constexpr (std::is_same()) { - return schema::Type{.value = - schema::Type::StringEnum{.values = _t.values_}}; - - } else if constexpr (std::is_same()) { - auto properties = std::map(); - auto required = std::vector(); - for (const auto& [k, v] : _t.types_) { - properties[k] = type_to_json_schema_type(v); - if (!is_optional(v)) { - required.push_back(k); - } - } - auto additional_properties = - _t.additional_properties_ - ? std::make_shared( - type_to_json_schema_type(*_t.additional_properties_)) - : std::shared_ptr(); - return schema::Type{.value = schema::Type::Object{ - .properties = properties, - .required = required, - .additionalProperties = additional_properties}}; - - } else if constexpr (std::is_same()) { - return schema::Type{.value = schema::Type::AnyOf{ - .anyOf = {type_to_json_schema_type(*_t.type_), - schema::Type{schema::Type::Null{}}}}}; - - } else if constexpr (std::is_same()) { - return schema::Type{ - .value = schema::Type::Reference{.ref = "#/definitions/" + _t.name_}}; - - } else if constexpr (std::is_same()) { - return schema::Type{.value = schema::Type::StringMap{ - .additionalProperties = Ref::make( - type_to_json_schema_type(*_t.value_type_))}}; - - } else if constexpr (std::is_same()) { - auto items = std::vector(); - for (const auto& t : _t.types_) { - items.emplace_back(type_to_json_schema_type(t)); - } - return schema::Type{.value = schema::Type::Tuple{.prefixItems = items}}; - - } else if constexpr (std::is_same()) { - return schema::Type{.value = schema::Type::TypedArray{ - .items = Ref::make( - type_to_json_schema_type(*_t.type_))}}; - - } else if constexpr (std::is_same()) { - return handle_validation_type(*_t.type_, _t.validation_); - - } else { - static_assert(rfl::always_false_v, "Not all cases were covered."); - } - }; - - return rfl::visit(handle_variant, _type.variant_); -} - -} // namespace rfl::json - -// ---------------------------------------------------------------------------- - -#include "rfl/parsing/schema/Type.hpp" - -namespace rfl::parsing::schema { - -/// Requires a lot of template instantiation, so we do not want this to be -/// inlined. - -Type::Type() : variant_() {} - -Type::Type(const VariantType& _variant) : variant_(_variant) {} - -Type::~Type() = default; - -} // namespace rfl::parsing::schema - -// ---------------------------------------------------------------------------- +// This file include all other source files, so that the user of the library +// don't need to add multiple source files into their build. +// Also, this speeds up compile time, compared to multiple separate .cpp files +// compilation. + +#include "Generic.cpp" +#include "to_schema.cpp" +#include "Type.cpp" diff --git a/src/to_schema.cpp b/src/to_schema.cpp new file mode 100644 index 00000000..8b51f472 --- /dev/null +++ b/src/to_schema.cpp @@ -0,0 +1,279 @@ +/* + +MIT License + +Copyright (c) 2023-2024 Code17 GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "rfl/json/to_schema.hpp" + +namespace rfl::json { + +schema::Type type_to_json_schema_type(const parsing::schema::Type& _type); + +bool is_optional(const parsing::schema::Type& _t) { + const auto handle = [](const auto& _v) -> bool { + using T = std::remove_cvref_t; + return std::is_same(); + }; + return rfl::visit(handle, _t.variant_); +} + +std::string numeric_type_to_string(const parsing::schema::Type& _type) { + const auto handle_variant = [](const auto& _t) -> std::string { + using T = std::remove_cvref_t; + using Type = parsing::schema::Type; + if constexpr (std::is_same() || + std::is_same() || + std::is_same() || + std::is_same() || + std::is_same()) { + return schema::Type::Integer{}.type.str(); + } else { + return schema::Type::Number{}.type.str(); + } + }; + return rfl::visit(handle_variant, _type.variant_); +} + +schema::Type handle_validation_type( + const parsing::schema::Type& _type, + const parsing::schema::ValidationType& _validation_type) { + auto handle_variant = [&](const auto& _v) -> schema::Type { + using T = std::remove_cvref_t; + using ValidationType = parsing::schema::ValidationType; + if constexpr (std::is_same()) { + auto all_of = std::vector(); + for (const auto& t : _v.types_) { + all_of.emplace_back(handle_validation_type(_type, t)); + } + return schema::Type{.value = schema::Type::AllOf{.allOf = all_of}}; + + } else if constexpr (std::is_same()) { + auto any_of = std::vector(); + for (const auto& t : _v.types_) { + any_of.emplace_back(handle_validation_type(_type, t)); + } + return schema::Type{.value = schema::Type::AnyOf{.anyOf = any_of}}; + + } else if constexpr (std::is_same()) { + auto one_of = std::vector(); + for (const auto& t : _v.types_) { + one_of.emplace_back(handle_validation_type(_type, t)); + } + return schema::Type{.value = schema::Type::OneOf{.oneOf = one_of}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::Regex{.pattern = _v.pattern_}}; + + } else if constexpr (std::is_same()) { + auto t = type_to_json_schema_type(_type); + const auto to_size = [](const auto _v) { + return static_cast(_v); + }; + auto handle_size_variant = [&](auto& _t, const auto& _size_limit) { + using U = std::remove_cvref_t; + using V = std::remove_cvref_t; + if constexpr (std::is_same() || + std::is_same()) { + if constexpr (std::is_same()) { + _t.minSize = _size_limit.value_.visit(to_size); + return t; + + } else if constexpr (std::is_same()) { + _t.maxSize = _size_limit.value_.visit(to_size); + return t; + + } else if constexpr (std::is_same()) { + _t.minSize = _size_limit.value_.visit(to_size); + _t.maxSize = _size_limit.value_.visit(to_size); + return t; + + } else if constexpr (std::is_same() || + std::is_same()) { + V v; + for (const auto& limiter : _size_limit.types_) { + v.types_.push_back(ValidationType{ValidationType::Size{ + .size_limit_ = rfl::Ref::make(limiter)}}); + } + return handle_validation_type(_type, ValidationType{.variant_ = v}); + } + } + return t; + }; + + return rfl::visit(handle_size_variant, t.value, _v.size_limit_->variant_); + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::ExclusiveMaximum{ + .exclusiveMaximum = _v.value_, + .type = numeric_type_to_string(_type)}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::ExclusiveMinimum{ + .exclusiveMinimum = _v.value_, + .type = numeric_type_to_string(_type)}}; + + } else if constexpr (std::is_same()) { + return schema::Type{ + .value = schema::Type::Maximum{ + .maximum = _v.value_, .type = numeric_type_to_string(_type)}}; + + } else if constexpr (std::is_same()) { + return schema::Type{ + .value = schema::Type::Minimum{ + .minimum = _v.value_, .type = numeric_type_to_string(_type)}}; + + } else if constexpr (std::is_same()) { + const auto maximum = schema::Type{ + .value = schema::Type::Maximum{ + .maximum = _v.value_, .type = numeric_type_to_string(_type)}}; + const auto minimum = schema::Type{ + .value = schema::Type::Minimum{ + .minimum = _v.value_, .type = numeric_type_to_string(_type)}}; + return schema::Type{.value = + schema::Type::AllOf{.allOf = {maximum, minimum}}}; + + } else if constexpr (std::is_same()) { + const auto excl_maximum = + schema::Type{.value = schema::Type::ExclusiveMaximum{ + .exclusiveMaximum = _v.value_, + .type = numeric_type_to_string(_type)}}; + const auto excl_minimum = + schema::Type{.value = schema::Type::ExclusiveMinimum{ + .exclusiveMinimum = _v.value_, + .type = numeric_type_to_string(_type)}}; + return schema::Type{ + .value = schema::Type::AnyOf{.anyOf = {excl_maximum, excl_minimum}}}; + + } else { + static_assert(rfl::always_false_v, "Not all cases were covered."); + } + }; + + return rfl::visit(handle_variant, _validation_type.variant_); +} + +schema::Type type_to_json_schema_type(const parsing::schema::Type& _type) { + auto handle_variant = [](const auto& _t) -> schema::Type { + using T = std::remove_cvref_t; + using Type = parsing::schema::Type; + if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::Boolean{}}; + + } else if constexpr (std::is_same() || + std::is_same() || + std::is_same() || + std::is_same() || + std::is_same()) { + return schema::Type{.value = schema::Type::Integer{}}; + + } else if constexpr (std::is_same() || + std::is_same()) { + return schema::Type{.value = schema::Type::Number{}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::String{}}; + + } else if constexpr (std::is_same()) { + auto any_of = std::vector(); + for (const auto& t : _t.types_) { + any_of.emplace_back(type_to_json_schema_type(t)); + } + return schema::Type{.value = schema::Type::AnyOf{.anyOf = any_of}}; + + } else if constexpr (std::is_same()) { + auto res = type_to_json_schema_type(*_t.type_); + const auto update_prediction = [&](auto _v) -> schema::Type { + _v.description = _t.description_; + return schema::Type{_v}; + }; + return rfl::visit(update_prediction, res.value); + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::FixedSizeTypedArray{ + .items = Ref::make( + type_to_json_schema_type(*_t.type_)), + .minItems = _t.size_, + .maxItems = _t.size_}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = + schema::Type::StringEnum{.values = _t.values_}}; + + } else if constexpr (std::is_same()) { + auto properties = std::map(); + auto required = std::vector(); + for (const auto& [k, v] : _t.types_) { + properties[k] = type_to_json_schema_type(v); + if (!is_optional(v)) { + required.push_back(k); + } + } + auto additional_properties = + _t.additional_properties_ + ? std::make_shared( + type_to_json_schema_type(*_t.additional_properties_)) + : std::shared_ptr(); + return schema::Type{.value = schema::Type::Object{ + .properties = properties, + .required = required, + .additionalProperties = additional_properties}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::AnyOf{ + .anyOf = {type_to_json_schema_type(*_t.type_), + schema::Type{schema::Type::Null{}}}}}; + + } else if constexpr (std::is_same()) { + return schema::Type{ + .value = schema::Type::Reference{.ref = "#/definitions/" + _t.name_}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::StringMap{ + .additionalProperties = Ref::make( + type_to_json_schema_type(*_t.value_type_))}}; + + } else if constexpr (std::is_same()) { + auto items = std::vector(); + for (const auto& t : _t.types_) { + items.emplace_back(type_to_json_schema_type(t)); + } + return schema::Type{.value = schema::Type::Tuple{.prefixItems = items}}; + + } else if constexpr (std::is_same()) { + return schema::Type{.value = schema::Type::TypedArray{ + .items = Ref::make( + type_to_json_schema_type(*_t.type_))}}; + + } else if constexpr (std::is_same()) { + return handle_validation_type(*_t.type_, _t.validation_); + + } else { + static_assert(rfl::always_false_v, "Not all cases were covered."); + } + }; + + return rfl::visit(handle_variant, _type.variant_); +} + +} // namespace rfl::json