#ifndef RFL_PARSING_PARSER_VARIANT_HPP_ #define RFL_PARSING_PARSER_VARIANT_HPP_ #include #include #include #include #include "../Ref.hpp" #include "../Result.hpp" #include "../always_false.hpp" #include "FieldVariantParser.hpp" #include "Parser_base.hpp" #include "schema/Type.hpp" #include "to_single_error_message.hpp" namespace rfl { namespace parsing { template requires AreReaderAndWriter> class Parser, ProcessorsType> { public: using InputVarType = typename R::InputVarType; using OutputVarType = typename W::OutputVarType; static Result> read(const R& _r, const InputVarType& _var) noexcept { if constexpr (internal::all_fields>()) { return FieldVariantParser::read( _r, _var ); } else { std::optional> result; std::vector errors; read_variant(_r, _var, &result, &errors); if (result) { return std::move(*result); } else { return Error(to_single_error_message( errors, "Could not parse the variant. Each of the " "possible alternatives failed " "for the following reasons: ", 100000 )); } } } template static void write( const W& _w, const std::variant& _variant, const P& _parent ) noexcept { if constexpr (internal::all_fields>()) { FieldVariantParser::write( _w, _variant, _parent ); } else { const auto handle = [&](const auto& _v) { using Type = std::remove_cvref_t; Parser::write(_w, _v, _parent); }; return std::visit(handle, _variant); } } template static schema::Type to_schema( std::map* _definitions, std::vector _types = {} ) { if constexpr (internal::all_fields>()) { return FieldVariantParser:: to_schema(_definitions); } else { using Type = schema::Type; constexpr size_t size = sizeof...(FieldTypes); if constexpr (_i == size) { return Type {Type::AnyOf {.types_ = _types}}; } else { using U = std::remove_cvref_t< std::variant_alternative_t<_i, std::variant>>; _types.push_back( Parser::to_schema(_definitions) ); return to_schema<_i + 1>(_definitions, std::move(_types)); } } } private: template static void read_variant( const R& _r, const InputVarType& _var, std::optional>* _result, std::vector* _errors ) noexcept { constexpr size_t size = sizeof...(FieldTypes); if constexpr (_i < size) { using AltType = std::remove_cvref_t< std::variant_alternative_t<_i, std::variant>>; auto res = Parser::read(_r, _var); if (res) { *_result = std::move(*res); return; } else { _errors->emplace_back(*res.error()); return read_variant<_i + 1>(_r, _var, _result, _errors); } } } }; } // namespace parsing } // namespace rfl #endif