1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
#ifndef RFL_PARSING_FIELDVARIANTREADER_HPP_
#define RFL_PARSING_FIELDVARIANTREADER_HPP_
#include <array>
#include <optional>
#include <sstream>
#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
#include "../Result.hpp"
#include "../Variant.hpp"
#include "../internal/is_array.hpp"
#include "../internal/nth_element_t.hpp"
namespace rfl::parsing {
template <class R, class W, class ProcessorsType, class... FieldTypes>
class FieldVariantReader {
private:
using InputVarType = typename R::InputVarType;
using FieldVariantType = rfl::Variant<FieldTypes...>;
using ResultType = Result<FieldVariantType>;
public:
FieldVariantReader(const R* _r,
std::optional<Result<FieldVariantType>>* _field_variant)
: r_(_r), field_variant_(_field_variant) {}
~FieldVariantReader() = default;
void read(const std::string_view& _disc_value,
const InputVarType& _var) const noexcept {
try_matching_fields(
_disc_value, _var,
std::make_integer_sequence<int, sizeof...(FieldTypes)>());
if (!*field_variant_) {
std::stringstream stream;
stream << "Could not parse rfl::Variant, could not match field named "
"'"
<< _disc_value << "'.";
*field_variant_ = error(stream.str());
}
}
private:
template <int... _is>
void try_matching_fields(const std::string_view& _disc_value,
const InputVarType& _var,
std::integer_sequence<int, _is...>) const noexcept {
(try_one<_is>(_disc_value, _var), ...);
}
template <int _i>
void try_one(const std::string_view& _disc_value,
const InputVarType& _var) const noexcept {
using FieldType =
std::remove_cvref_t<internal::nth_element_t<_i, FieldTypes...>>;
using ValueType = std::remove_cvref_t<typename FieldType::Type>;
constexpr auto key = FieldType::name_.string_view();
if (key == _disc_value) {
const auto to_variant = [](ValueType&& _val) {
return rfl::Variant<FieldTypes...>(FieldType(std::move(_val)));
};
const auto embellish_error = [&](const Error& _e) {
std::stringstream stream;
stream << "Could not parse rfl::Variant with field '"
<< std::string(_disc_value) << "': " << _e.what();
return Error(stream.str());
};
*field_variant_ = Parser<R, W, ValueType, ProcessorsType>::read(*r_, _var)
.transform(to_variant)
.transform_error(embellish_error);
}
}
private:
/// The underlying reader.
const R* r_;
/// The underlying field variant.
std::optional<Result<FieldVariantType>>* field_variant_;
};
} // namespace rfl::parsing
#endif
|