#ifndef RFL_PARSING_MAPREADER_HPP_ #define RFL_PARSING_MAPREADER_HPP_ #include #include #include #include #include #include "../Result.hpp" #include "../always_false.hpp" namespace rfl::parsing { template class MapReader { private: using InputVarType = typename R::InputVarType; using KeyType = std::remove_cvref_t; using ValueType = std::remove_cvref_t; public: MapReader(const R* _r, MapType* _map, std::vector* _errors) : r_(_r), map_(_map), errors_(_errors) {} ~MapReader() = default; void read(const std::string_view& _name, const InputVarType& _var) const noexcept { auto res = get_pair(_name, _var); if (res) { map_->emplace(std::move(*res)); } else { errors_->push_back(Error("Failed to parse field '" + std::string(_name) + "': " + res.error()->what())); } } private: template Result key_to_numeric(auto& _pair) const noexcept { try { if constexpr (std::is_integral_v && std::is_signed_v) { return static_cast(std::stoll(_pair.first)); } else if constexpr (std::is_integral_v && std::is_unsigned_v) { return static_cast(std::stoull(_pair.first)); } else if constexpr (std::is_floating_point_v) { return static_cast(std::stod(_pair.first)); } else { static_assert(always_false_v, "Unsupported type"); } } catch (std::exception& e) { return Error(e.what()); } } Result> make_key(auto& _pair) const noexcept { const auto to_pair = [&](auto _key) -> Result> { try { return std::make_pair(KeyType(std::move(_key)), std::move(_pair.second)); } catch (std::exception& e) { return Error(e.what()); } }; if constexpr (std::is_integral_v || std::is_floating_point_v) { return key_to_numeric(_pair).and_then(to_pair); } else if constexpr (internal::has_reflection_type_v) { using ReflT = typename KeyType::ReflectionType; if constexpr (std::is_integral_v || std::is_floating_point_v) { return key_to_numeric(_pair).and_then(to_pair); } else { return to_pair(_pair.first); } } else { return std::move(_pair); } } Result> get_pair( const std::string_view& _name, const InputVarType& _var) const noexcept { const auto to_pair = [&](ValueType&& _val) { auto pair = std::make_pair(std::string(_name), std::move(_val)); return make_key(pair); }; return Parser, ProcessorsType>::read( *r_, _var) .and_then(to_pair); } private: /// The underlying reader. const R* r_; /// The underlying map. MapType* map_; /// Collects any errors we may have come across. std::vector* errors_; }; } // namespace rfl::parsing #endif