#ifndef RFL_PARSING_VECTORPARSER_HPP_ #define RFL_PARSING_VECTORPARSER_HPP_ #include #include #include #include #include #include "../Result.hpp" #include "../always_false.hpp" #include "MapParser.hpp" #include "Parent.hpp" #include "Parser_base.hpp" #include "VectorReader.hpp" #include "is_forward_list.hpp" #include "is_map_like.hpp" #include "is_map_like_not_multimap.hpp" #include "is_set_like.hpp" #include "schema/Type.hpp" namespace rfl { namespace parsing { /// This can be used for data structures that would be expressed as array in /// serialized format (std::vector, std::set, std::deque, ...), /// but also includes map-like types, when the key is not of type /// std::string. template requires AreReaderAndWriter struct VectorParser { public: using InputArrayType = typename R::InputArrayType; using InputVarType = typename R::InputVarType; using OutputArrayType = typename W::OutputArrayType; using OutputVarType = typename W::OutputVarType; using ParentType = Parent; using T = typename VecType::value_type; static Result read(const R& _r, const InputVarType& _var) noexcept { if constexpr (treat_as_map()) { return MapParser::read(_r, _var); } else if constexpr (is_forward_list()) { const auto to_forward_list = [](auto&& vec) -> std::forward_list { std::forward_list list; for (auto it = vec.rbegin(); it != vec.rend(); ++it) { list.emplace_front(std::move(*it)); } return list; }; return Parser, ProcessorsType>::read(_r, _var) .transform(to_forward_list); } else { const auto parse = [&](const InputArrayType& _arr ) -> Result { VecType vec; auto vector_reader = VectorReader(&_r, &vec); const auto err = _r.read_array(vector_reader, _arr); if (err) { return *err; } return vec; }; return _r.to_array(_var).and_then(parse); } } template static void write(const W& _w, const VecType& _vec, const P& _parent) noexcept { if constexpr (treat_as_map()) { MapParser::write(_w, _vec, _parent); } else { auto arr = ParentType::add_array( _w, std::distance(_vec.begin(), _vec.end()), _parent ); const auto new_parent = typename ParentType::Array {&arr}; for (const auto& v : _vec) { Parser, ProcessorsType>::write( _w, v, new_parent ); } _w.end_array(&arr); } } /// Generates a schema for the underlying type. static schema::Type to_schema( std::map* _definitions ) { using Type = schema::Type; return Type {Type::TypedArray { .type_ = Ref::make( Parser::to_schema(_definitions) ) }}; } private: static constexpr bool treat_as_map() { if constexpr (is_map_like_not_multimap()) { if constexpr (internal::has_reflection_type_v< typename T::first_type>) { using U = std::remove_cvref_t; return std::is_same() || std::is_integral_v || std::is_floating_point_v; // We do not need std::string here, it is already caught by the // template specialization. } else if constexpr (std::is_integral_v || std::is_floating_point_v< typename T::first_type>) { return true; } else { return false; } } else { return false; } } }; } // namespace parsing } // namespace rfl #endif