#ifndef RFL_ONEOF_HPP_ #define RFL_ONEOF_HPP_ #include #include #include #include "Result.hpp" #include "parsing/schema/ValidationType.hpp" namespace rfl { /// Requires that all of the contraints C and Cs be true. template struct OneOf { template static rfl::Result validate(const T& _value) noexcept { return validate_impl(_value, {}); } template static parsing::schema::ValidationType to_schema() { using ValidationType = parsing::schema::ValidationType; const auto types = std::vector( {C::template to_schema(), Cs::template to_schema()...} ); return ValidationType {ValidationType::OneOf {.types_ = types}}; } private: static Error make_error_message(const std::vector& _errors) { std::string msg = "Expected exactly 1 out of " + std::to_string(sizeof...(Cs) + 1) + " validations to pass, but " + std::to_string(sizeof...(Cs) + 1 - _errors.size()) + " of them did. The following errors were generated: "; for (size_t i = 0; i < _errors.size(); ++i) { msg += "\n" + std::to_string(i + 1) + ") " + _errors.at(i).what(); } return Error(msg); } template static rfl::Result validate_impl(const T& _value, std::vector _errors) { const auto push_back = [&](Error&& _err) -> rfl::Result { _errors.emplace_back(std::forward(_err)); return _err; }; const auto next_validation = [&](rfl::Result&& _r) -> rfl::Result { _r.or_else(push_back); if constexpr (sizeof...(Tail) == 0) { if (_errors.size() == sizeof...(Cs)) { return _value; } return make_error_message(_errors); } else { return validate_impl( _value, std::forward>(_errors) ); } }; return Head::validate(_value) .and_then(next_validation) .or_else(next_validation); } }; } // namespace rfl #endif