Files
mcc/mcc_deserializer.h
Timur A. Fatkhullin ae91e7320c ...
2026-02-02 02:36:23 +03:00

280 lines
8.2 KiB
C++

#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<mcc::impl::MccDeserializerErrorCode> : 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<MccDeserializerErrorCode>(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<int>(ec), MccDeserializerCategory::get());
}
template <mcc_error_c RetT>
struct mcc_deserializer_interface_t {
virtual ~mcc_deserializer_interface_t() = default;
typedef RetT error_t;
template <std::derived_from<mcc_deserializer_interface_t> SelfT, traits::mcc_input_char_range R, typename ValueT>
RetT operator()(this SelfT&& self, R const& input, ValueT& value)
{
return std::forward<SelfT>(self)(input, value);
}
protected:
mcc_deserializer_interface_t() = default;
};
template <typename T>
concept mcc_deserializer_c = std::derived_from<T, mcc_deserializer_interface_t<typename T::error_t>>;
namespace details
{
struct MccDeserializerBase : mcc_deserializer_interface_t<impl::MccError> {
using typename mcc_deserializer_interface_t<impl::MccError>::error_t;
virtual ~MccDeserializerBase() = default;
// set delimiter for elements of the range-type serialized value
template <traits::mcc_input_char_range R>
void setSeqDelimiter(R const& delim)
{
if constexpr (std::is_array_v<std::decay_t<R>>) {
setSeqDelimiter(std::string_view{delim});
} else {
_seqDelimiter.clear();
std::ranges::copy(delim, std::back_inserter(_seqDelimiter));
}
}
template <traits::mcc_view_or_output_char_range R>
R getSeqDelimiter() const
{
if constexpr (std::same_as<R, decltype(_seqDelimiter)>) {
return _seqDelimiter;
} else if constexpr (std::ranges::view<R>) {
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<std::string>();
}
template <traits::mcc_input_char_range R>
void setElemDelimiter(R const& delim)
{
if constexpr (std::is_array_v<std::decay_t<R>>) {
setElemDelimiter(std::string_view{delim});
} else {
_elementDelimiter.clear();
std::ranges::copy(delim, std::back_inserter(_seqDelimiter));
}
}
template <traits::mcc_view_or_output_char_range R>
R getElemDelimiter() const
{
if constexpr (std::same_as<R, decltype(_seqDelimiter)>) {
return _elementDelimiter;
} else if constexpr (std::ranges::view<R>) {
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<std::string>();
}
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 <typename VT, typename R>
requires(std::ranges::input_range<R> && std::same_as<VT, std::ranges::range_value_t<R>>)
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 <typename VT>
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<VT>) {
auto v = mcc::utils::numFromStr<VT>(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>) {
VT r;
if constexpr (traits::mcc_array_c<VT>) {
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<VT>) {
using el_t = std::ranges::range_value_t<VT>;
static_assert(std::ranges::output_range<VT, el_t>, "INVALID RANGE TYPE!!!");
// no reference or constants allowed
static_assert(std::is_reference_v<el_t> || std::is_const_v<el_t>, "INVALID RANGE ELEMENT TYPE!!!");
MccDeserializer<el_t> dsr;
return deserializingRange<el_t>(dsr, input, value);
} else {
static_assert(false, "UNSUPPORTED VALUE TYPE!!!");
}
return MccDeserializerErrorCode::ERROR_OK;
}
};
} // namespace mcc::impl