draconisplusplus/include/rfl/parsing/FieldVariantReader.hpp

86 lines
2.5 KiB
C++
Raw Normal View History

2024-05-31 22:59:00 -04:00
#ifndef RFL_PARSING_FIELDVARIANTREADER_HPP_
#define RFL_PARSING_FIELDVARIANTREADER_HPP_
#include <array>
#include <optional>
#include <string_view>
#include <type_traits>
#include <variant>
#include <vector>
#include "../Result.hpp"
#include "../internal/is_array.hpp"
namespace rfl::parsing {
2024-06-08 14:10:59 -04:00
template <class R, class W, class ProcessorsType, class... FieldTypes>
class FieldVariantReader {
private:
using InputVarType = typename R::InputVarType;
using FieldVariantType = std::variant<FieldTypes...>;
using ResultType = Result<FieldVariantType>;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
public:
2024-06-16 00:13:15 -04:00
FieldVariantReader(const R* _r, std::optional<Result<FieldVariantType>>* _field_variant)
: r_(_r), field_variant_(_field_variant) {}
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
~FieldVariantReader() = default;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
template <size_t _i = 0>
2024-06-16 00:13:15 -04:00
void read(const std::string_view& _disc_value, const InputVarType& _var) const noexcept {
2024-06-08 14:10:59 -04:00
if constexpr (_i < sizeof...(FieldTypes)) {
if constexpr (_i == 0) {
if (*field_variant_) {
*field_variant_ = Error(
2024-06-16 00:13:15 -04:00
"Could not parse: Expected the object to have "
"exactly one field, but found more than one."
2024-06-08 15:53:06 -04:00
);
2024-06-08 14:10:59 -04:00
return;
}
2024-05-31 22:59:00 -04:00
}
2024-06-16 00:13:15 -04:00
using FieldType =
std::remove_cvref_t<typename std::tuple_element<_i, std::tuple<FieldTypes...>>::type>;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
using ValueType = std::remove_cvref_t<typename FieldType::Type>;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
constexpr auto key = FieldType::name_.string_view();
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
if (key == _disc_value) {
const auto to_variant = [](ValueType&& _val) {
return std::variant<FieldTypes...>(FieldType(std::move(_val)));
};
const auto embellish_error = [&](const Error& _e) {
2024-06-08 15:53:06 -04:00
return Error(
2024-06-16 00:13:15 -04:00
"Could not parse std::variant with field '" + std::string(_disc_value) +
"': " + _e.what()
2024-06-08 15:53:06 -04:00
);
2024-06-08 14:10:59 -04:00
};
2024-06-16 00:13:15 -04:00
*field_variant_ = Parser<R, W, ValueType, ProcessorsType>::read(*r_, _var)
.transform(to_variant)
.or_else(embellish_error);
2024-06-08 14:10:59 -04:00
return;
} else {
read<_i + 1>(_disc_value, _var);
}
2024-05-31 22:59:00 -04:00
} else {
2024-06-08 14:10:59 -04:00
*field_variant_ = Error(
2024-06-16 00:13:15 -04:00
"Could not parse std::variant, could not match field named "
"'" +
std::string(_disc_value) + "'."
2024-06-08 15:53:06 -04:00
);
2024-05-31 22:59:00 -04:00
}
}
2024-06-08 14:10:59 -04:00
private:
/// The underlying reader.
const R* r_;
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
/// The underlying field variant.
std::optional<Result<FieldVariantType>>* field_variant_;
};
2024-05-31 22:59:00 -04:00
2024-06-08 14:10:59 -04:00
} // namespace rfl::parsing
2024-05-31 22:59:00 -04:00
#endif