#pragma once /**************************************************************************************** * * * MOUNT CONTROL COMPONENTS LIBRARY * * * * * * IMPLEMENTATION OF DESERIALIZER CLASSES * * * ****************************************************************************************/ #include "mcc_concepts.h" #include "mcc_constants.h" #include "mcc_error.h" namespace mcc::impl { enum class MccDeserializerErrorCode : int { ERROR_OK, ERROR_UNDERLYING_DESERIALIZER, ERROR_INVALID_SERIAL_VALUE, ERROR_COORD_TRANSFORM }; } // namespace mcc::impl namespace std { template <> class is_error_code_enum : public true_type { }; } // namespace std namespace mcc::impl { // error category struct MccDeserializerCategory : public std::error_category { MccDeserializerCategory() : std::error_category() {} const char* name() const noexcept { return "MCC-DESERIALIZER-ERR-CATEGORY"; } std::string message(int ec) const { MccDeserializerErrorCode err = static_cast(ec); switch (err) { case MccDeserializerErrorCode::ERROR_OK: return "OK"; case MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER: return "error returned by underlying deserializer"; case MccDeserializerErrorCode::ERROR_INVALID_SERIAL_VALUE: return "invalid serialized value"; case MccDeserializerErrorCode::ERROR_COORD_TRANSFORM: return "coordinates transformation error"; default: return "UNKNOWN"; } } static const MccDeserializerCategory& get() { static const MccDeserializerCategory constInst; return constInst; } }; inline std::error_code make_error_code(MccDeserializerErrorCode ec) { return std::error_code(static_cast(ec), MccDeserializerCategory::get()); } template struct mcc_deserializer_interface_t { virtual ~mcc_deserializer_interface_t() = default; typedef RetT error_t; template SelfT, traits::mcc_input_char_range R, typename ValueT> RetT operator()(this SelfT&& self, R const& input, ValueT& value) { return std::forward(self)(input, value); } protected: mcc_deserializer_interface_t() = default; }; template concept mcc_deserializer_c = std::derived_from>; namespace details { struct MccDeserializerBase : mcc_deserializer_interface_t { using typename mcc_deserializer_interface_t::error_t; virtual ~MccDeserializerBase() = default; // set delimiter for elements of the range-type serialized value template void setSeqDelimiter(R const& delim) { if constexpr (std::is_array_v>) { setSeqDelimiter(std::string_view{delim}); } else { _seqDelimiter.clear(); std::ranges::copy(delim, std::back_inserter(_seqDelimiter)); } } template R getSeqDelimiter() const { if constexpr (std::same_as) { return _seqDelimiter; } else if constexpr (std::ranges::view) { return R{_seqDelimiter.begin(), _seqDelimiter.end()}; } else { R r; std::ranges::copy(_seqDelimiter, std::back_inserter(r)); return r; } } std::string getSeqDelimiter() const { return getSeqDelimiter(); } template void setElemDelimiter(R const& delim) { if constexpr (std::is_array_v>) { setElemDelimiter(std::string_view{delim}); } else { _elementDelimiter.clear(); std::ranges::copy(delim, std::back_inserter(_seqDelimiter)); } } template R getElemDelimiter() const { if constexpr (std::same_as) { return _elementDelimiter; } else if constexpr (std::ranges::view) { return R{_elementDelimiter.begin(), _elementDelimiter.end()}; } else { R r; std::ranges::copy(_elementDelimiter, std::back_inserter(r)); return r; } } std::string getElemDelimiter() const { return getElemDelimiter(); } protected: MccDeserializerBase() = default; // delimiter for sequence of serialized values std::string _seqDelimiter{MCC_DEFAULT_SEQ_DELIMITER}; // delimiter for aggregative (multi-element) serialized value std::string _elementDelimiter{MCC_DEFAULT_ELEM_DELIMITER}; template requires(std::ranges::input_range && std::same_as>) error_t deserializingRange(mcc_deserializer_c auto& dsr, traits::mcc_input_char_range auto const& input, R& r) const { if (std::ranges::size(input) == 0) { // ignore empy input return MccDeserializerErrorCode::ERROR_OK; } auto r_str = std::views::split(input, _seqDelimiter); VT val; auto it = r.begin(); for (auto const& el : r_str) { auto err = dsr(el, val); if (err) { return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER); } if (it == r.end()) { std::back_inserter(r) = val; it = r.end(); } else { *it = val; ++it; } } return MccDeserializerErrorCode::ERROR_OK; } }; } // namespace details // template class MccDeserializer : public details::MccDeserializerBase { public: using typename details::MccDeserializerBase::error_t; virtual ~MccDeserializer() = default; error_t operator()(traits::mcc_input_char_range auto const& input, VT& value) { if constexpr (std::is_arithmetic_v) { auto v = mcc::utils::numFromStr(trimSpaces(input)); if (!v.has_value()) { return MccDeserializerErrorCode::ERROR_INVALID_SERIAL_VALUE; } value = v.value(); } else if constexpr (mcc::traits::mcc_output_char_range) { VT r; if constexpr (traits::mcc_array_c) { size_t N = std::ranges::size(r) <= std::ranges::size(input) ? std::ranges::size(r) : std::ranges::size(input); for (size_t i = 0; i < N; ++i) { r[i] = input[i]; } if (std::ranges::size(r) > N) { for (size_t i = N; i < std::ranges::size(r); ++i) { r[i] = '\0'; } } } else { std::ranges::copy(input, std::back_inserter(r)); } value = r; } else if constexpr (std::ranges::range) { using el_t = std::ranges::range_value_t; static_assert(std::ranges::output_range, "INVALID RANGE TYPE!!!"); // no reference or constants allowed static_assert(std::is_reference_v || std::is_const_v, "INVALID RANGE ELEMENT TYPE!!!"); MccDeserializer dsr; return deserializingRange(dsr, input, value); } else { static_assert(false, "UNSUPPORTED VALUE TYPE!!!"); } return MccDeserializerErrorCode::ERROR_OK; } }; } // namespace mcc::impl