#ifndef RFL_PARSING_TUPLEPARSER_HPP_ #define RFL_PARSING_TUPLEPARSER_HPP_ #include #include #include #include #include "../Result.hpp" #include "../Tuple.hpp" #include "../always_false.hpp" #include "../internal/nth_element_t.hpp" #include "../internal/ptr_cast.hpp" #include "Parent.hpp" #include "TupleReader.hpp" #include "call_destructors_on_tuple_where_necessary.hpp" #include "schema/Type.hpp" #include "schemaful/IsSchemafulReader.hpp" #include "schemaful/IsSchemafulWriter.hpp" #include "schemaful/tuple_to_named_tuple.hpp" #include "schemaful/tuple_to_named_tuple_t.hpp" namespace rfl::parsing { template requires AreReaderAndWriter struct TupleParser { public: using InputArrayType = typename R::InputArrayType; using InputVarType = typename R::InputVarType; using ParentType = Parent; static Result read(const R& _r, const InputVarType& _var) noexcept { if constexpr (schemaful::IsSchemafulReader) { using NamedTupleType = schemaful::tuple_to_named_tuple_t; const auto to_tuple = [](auto&& _named_tuple) { return [&](std::integer_sequence) { return TupleType(std::move(rfl::get<_is>(_named_tuple))...); }(std::make_integer_sequence()); }; return Parser::read(_r, _var) .transform(to_tuple); } else { const auto parse = [&](const InputArrayType& _arr) -> Result { alignas(TupleType) unsigned char buf[sizeof(TupleType)]{}; auto ptr = internal::ptr_cast(&buf); const auto tuple_reader = TupleReader(&_r, ptr); auto err = _r.read_array(tuple_reader, _arr); if (err) { call_destructors_on_tuple_where_necessary(tuple_reader.num_set(), ptr); return error(*err); } err = tuple_reader.handle_missing_fields(); if (err) { call_destructors_on_tuple_where_necessary(tuple_reader.num_set(), ptr); return error(*err); } auto res = Result(std::move(*ptr)); call_destructors_on_tuple_where_necessary(tuple_reader.num_set(), ptr); return res; }; return _r.to_array(_var).and_then(parse); } } template static void write(const W& _w, const TupleType& _tup, const P& _parent) { if constexpr (schemaful::IsSchemafulWriter) { const auto named_tuple = schemaful::tuple_to_named_tuple(_tup); Parser, ProcessorsType>::write(_w, named_tuple, _parent); } else { constexpr auto size = rfl::tuple_size_v; auto arr = ParentType::add_array(_w, size, _parent); const auto new_parent = typename ParentType::Array{&arr}; to_array(_w, _tup, new_parent, std::make_integer_sequence()); _w.end_array(&arr); } } static schema::Type to_schema( std::map* _definitions) { std::vector types; build_schema( _definitions, &types, std::make_integer_sequence>()); return schema::Type{schema::Type::Tuple{.types_ = std::move(types)}}; } private: template static void add_to_schema(std::map* _definitions, std::vector* _types) noexcept { using U = std::remove_cvref_t>; _types->push_back(Parser::to_schema(_definitions)); } template static void build_schema(std::map* _definitions, std::vector* _types, std::integer_sequence) noexcept { (add_to_schema<_is>(_definitions, _types), ...); } template static void add_to_array(const W& _w, const TupleType& _tup, const P& _parent) { using NewFieldType = std::remove_cvref_t>; Parser::write(_w, rfl::get<_i>(_tup), _parent); } template static void to_array(const W& _w, const TupleType& _tup, const P& _parent, std::integer_sequence) { (add_to_array<_is>(_w, _tup, _parent), ...); } }; } // namespace rfl::parsing #endif