This commit is contained in:
2026-05-30 16:21:45 +03:00
parent 434521a435
commit 21d79a4cb5
6 changed files with 1073 additions and 46 deletions

518
common/adc_serialization.h Normal file
View File

@@ -0,0 +1,518 @@
#pragma once
/*
ABSTRACT DEVICE COMPONENTS LIBRARY
*/
#include <algorithm>
#include <concepts>
#include <ranges>
#include "adc_traits.h"
#include "adc_utils.h"
namespace adc
{
/* SERIALIZATION/DESERIALIZATION PROCESS ERROR */
template <typename T>
concept adc_serialization_error_c = std::default_initializable<T> && (std::convertible_to<T, bool> || requires {
(bool)T() == false; // default constucted value must be a "non-error"!
});
// default
typedef std::error_code adc_serialization_error_t;
/* SERIALIZATION/DESERIALIZATION PROCESS TUNING PARAMETERS */
// delimiter between items of serializing values sequence
static constexpr std::string_view adc_SERIALIZING_DEFAULT_SEQ_DELIMITER{";"};
// delimiter between items of aggregative (multi-element) serializing value
static constexpr std::string_view adc_SERIALIZING_DEFAULT_ELEM_DELIMITER{","};
template <typename T>
concept adc_serialization_params_c = std::copyable<T> && requires(T t) {
// delimiter between items of serializing values sequence
requires traits::adc_output_char_range<decltype(t.elem_delim)>;
// delimiter between items of aggregative (multi-element) serializing value
requires traits::adc_output_char_range<decltype(t.seq_delim)>;
// a format string for std::chrono::time_point types
requires traits::adc_output_char_range<decltype(t.timepoint_format)>;
};
// default serializatio/deserialization process parameters type
struct adc_serialization_params_t {
std::string elem_delim{adc_SERIALIZING_DEFAULT_ELEM_DELIMITER};
std::string seq_delim{adc_SERIALIZING_DEFAULT_SEQ_DELIMITER};
std::string timepoint_format{"{:%FT%T}"};
};
/* SERIALIZER/DESERIALIZER CONCEPTS */
template <adc_serialization_error_c RetT>
struct adc_serializer_interface_t {
virtual ~adc_serializer_interface_t() = default;
typedef RetT error_t;
template <std::derived_from<adc_serializer_interface_t> SelfT, traits::adc_output_char_range R, typename ValueT>
RetT operator()(this SelfT&& self, R& output, ValueT const& value)
{
return std::forward<SelfT>(self)(output, value);
}
template <std::derived_from<adc_serializer_interface_t> SelfT, traits::adc_output_char_range R, typename ValueT>
RetT operator()(this SelfT&& self, R& output, ValueT const& value, adc_serialization_params_c auto const& params)
{
return std::forward<SelfT>(self)(output, value, params);
}
protected:
adc_serializer_interface_t() = default;
};
template <typename T>
concept adc_serializer_c =
std::derived_from<T, adc_serializer_interface_t<typename T::error_t>> && requires(T t, const T t_const) {
// static const variable with name of the serializer
requires std::formattable<decltype(T::serializerName), char> && std::is_const_v<decltype(T::serializerName)>;
};
template <adc_serialization_error_c RetT>
struct adc_deserializer_interface_t {
virtual ~adc_deserializer_interface_t() = default;
typedef RetT error_t;
template <std::derived_from<adc_deserializer_interface_t> SelfT, traits::adc_input_char_range R, typename ValueT>
RetT operator()(this SelfT&& self, R const& input, ValueT& value)
{
return std::forward<SelfT>(self)(input, value);
}
template <std::derived_from<adc_deserializer_interface_t> SelfT, traits::adc_input_char_range R, typename ValueT>
RetT operator()(this SelfT&& self, R const& input, ValueT& value, adc_serialization_params_c auto& params)
{
return std::forward<SelfT>(self)(input, value, params);
}
protected:
adc_deserializer_interface_t() = default;
};
template <typename T>
concept adc_deserializer_c =
std::derived_from<T, adc_deserializer_interface_t<typename T::error_t>> && requires(T t, const T t_const) {
// static const variable with name of the deserializer
requires std::formattable<decltype(T::deserializerName), char> &&
std::is_const_v<decltype(T::deserializerName)>;
};
} // namespace adc
/* BASIC IMPLEMENTATION OF SERIALIZER AND DESERIALIZER CLASSES */
namespace adc
{
enum class AdcSerializerErrorCode : int { ERROR_OK, ERROR_UNDERLYING_SERIALIZER };
enum class AdcDeserializerErrorCode : int { ERROR_OK, ERROR_UNDERLYING_DESERIALIZER, ERROR_INVALID_SERIALIZED_VALUE };
} // namespace adc
namespace std
{
template <>
class is_error_code_enum<adc::AdcSerializerErrorCode> : public true_type
{
};
template <>
class is_error_code_enum<adc::AdcDeserializerErrorCode> : public true_type
{
};
} // namespace std
namespace adc
{
// error category
struct AdcSerializerCategory : public std::error_category {
AdcSerializerCategory() : std::error_category() {}
const char* name() const noexcept
{
return "Adc-SERIALIZER-ERR-CATEGORY";
}
std::string message(int ec) const
{
AdcSerializerErrorCode err = static_cast<AdcSerializerErrorCode>(ec);
switch (err) {
case AdcSerializerErrorCode::ERROR_OK:
return "OK";
case AdcSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER:
return "error returned by underlying serializer";
default:
return "UNKNOWN";
}
}
static const AdcSerializerCategory& get()
{
static const AdcSerializerCategory constInst;
return constInst;
}
};
// error category
struct AdcDeserializerCategory : public std::error_category {
AdcDeserializerCategory() : std::error_category() {}
const char* name() const noexcept
{
return "Adc-DESERIALIZER-ERR-CATEGORY";
}
std::string message(int ec) const
{
AdcDeserializerErrorCode err = static_cast<AdcDeserializerErrorCode>(ec);
switch (err) {
case AdcDeserializerErrorCode::ERROR_OK:
return "OK";
case AdcDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER:
return "error returned by underlying deserializer";
case AdcDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE:
return "invalid serialized value";
default:
return "UNKNOWN";
}
}
static const AdcDeserializerCategory& get()
{
static const AdcDeserializerCategory constInst;
return constInst;
}
};
/* BASE SERIALIZER CLASS (FOR IMPLEMENTATIONS BELOW) */
struct AdcSerializerBase : adc_serializer_interface_t<adc_serialization_error_t> {
virtual ~AdcSerializerBase() = default;
using typename adc_serializer_interface_t<adc_serialization_error_t>::error_t;
protected:
AdcSerializerBase() = default;
static void addElemDelimiter(traits::adc_output_char_range auto& output,
adc_serialization_params_c auto const& params)
{
std::format_to(std::back_inserter(output), "{}", params.elem_delim);
}
static void addSeqDelimiter(traits::adc_output_char_range auto& output,
adc_serialization_params_c auto const& params)
{
std::format_to(std::back_inserter(output), "{}", params.seq_delim);
}
template <typename VT, typename R>
requires(std::ranges::input_range<R> && std::same_as<VT, std::ranges::range_value_t<R>>)
static error_t serializeRange(adc_serializer_c auto& sr,
R const& r,
traits::adc_output_char_range auto& output,
adc_serialization_params_c auto const& params)
{
size_t i = 0, N = std::ranges::size(r);
for (auto const& el : r) {
auto err = sr(output, el, params);
if (err) {
return adc_deduced_err(err, AdcSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
}
if (++i < N) {
// AdcSerializerBase::addSeqDelimiter(output, params);
AdcSerializerBase::addElemDelimiter(output, params);
}
}
return AdcSerializerErrorCode::ERROR_OK;
}
};
/* BASE DESERIALIZER CLASS (FOR IMPLEMENTATIONS BELOW) */
struct AdcDeserializerBase : adc_deserializer_interface_t<adc_serialization_error_t> {
using typename adc_deserializer_interface_t<adc_serialization_error_t>::error_t;
virtual ~AdcDeserializerBase() = default;
protected:
AdcDeserializerBase() = default;
//
// empty == true, if the 'input' is empty or if all elements consist of only spaces
//
static std::vector<std::string_view> splitValueIntoElements(traits::adc_input_char_range auto const& input,
adc_serialization_params_c auto const& params,
bool& empty)
{
static_assert(std::ranges::contiguous_range<decltype(input)>, "NOT IMPLEMENTED FOR NON-CONTIGUIUS RANGES!!!");
std::vector<std::string_view> res;
if (std::ranges::size(input)) {
empty = true;
std::ranges::for_each(std::views::split(input, params.elem_delim), [&res, &empty](auto const& el) {
std::back_inserter(res) = utils::AdcTrimSpacesView<std::string_view, std::string_view>(
std::string_view{el.begin(), el.end()});
if (empty && res.back().size()) {
empty = false;
}
});
} else {
empty = true;
}
return res;
}
template <typename VT, std::ranges::output_range<VT> R, typename... DeserParamsT>
static error_t deserializingRange(adc_deserializer_c auto& dsr,
traits::adc_input_char_range auto const& input,
R& r,
adc_serialization_params_c auto const& params)
{
if (std::ranges::size(input) == 0) { // ignore an empty input, just return empty range?!!
r = R{};
return AdcDeserializerErrorCode::ERROR_OK;
}
// auto r_str = std::views::split(input, params.seq_delim);
auto r_str = std::views::split(input, params.elem_delim);
VT val;
auto it = r.begin();
for (auto const& el : r_str) {
// auto err = dsr(el, val, std::forward<DeserParamsT>(params)...);
auto err = dsr(el, val, params);
if (err) {
return adc_deduced_err(err, AdcDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
}
if (it == r.end()) {
if constexpr (!traits::adc_fixed_size_range<R>) {
std::back_inserter(r) = val;
it = r.end();
}
} else {
*it = val;
++it;
}
}
return AdcDeserializerErrorCode::ERROR_OK;
}
};
/* MAIN (FALLBACK) TEMPLATED IMPLEMENTATION OF SERIALIZER/DESERIALIZER */
template <typename VT>
struct AdcSerializer : AdcSerializerBase {
constexpr static std::string_view serializerName{"ADC-FALLBACK-SERIALIZER"};
template <adc_serialization_params_c ParamsT = adc_serialization_params_t>
error_t operator()(traits::adc_output_char_range auto& output,
VT const& value,
ParamsT const& params = adc_serialization_params_t{})
{
if constexpr (std::convertible_to<VT, std::string>) {
std::string s = value;
std::ranges::copy(s, std::back_inserter(output));
} else if constexpr (std::ranges::range<VT>) {
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
// special range (character sequence)
if constexpr (std::same_as<value_t, char>) {
std::ranges::copy(value, std::back_inserter(output));
} else {
AdcSerializer<value_t> sr;
return AdcSerializerBase::serializeRange<value_t>(sr, value, output, params);
}
} else if constexpr (traits::adc_tuple_like<VT>) {
return [&output, &params]<size_t I = 0>(this auto& self, VT& tp) -> error_t {
if constexpr (I < (std::tuple_size_v<VT> - 1)) {
auto err = AdcSerializer<std::tuple_element_t<I, VT>>{}(output, std::get<I>(tp), params);
if (err) {
return AdcSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER;
}
AdcSerializerBase::addElemDelimiter(output, params);
return self.template operator()<I + 1>(tp);
} else if constexpr (I < (std::tuple_size_v<VT> - 1)) { // the last element
auto err = AdcSerializer<std::tuple_element_t<I, VT>>{}(output, std::get<I>(tp), params);
if (err) {
return AdcSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER;
}
return AdcSerializerErrorCode::ERROR_OK;
}
}(value);
} else if constexpr (traits::adc_time_point_c<VT>) {
std::string_view fmt{params.timepoint_format};
std::vformat_to(std::back_inserter(output), fmt, std::make_format_args(value));
} else if constexpr (traits::adc_time_duration_c<VT>) {
std::format_to(std::back_inserter(output), "{}", value.count());
} else if constexpr (std::formattable<VT, char>) {
std::format_to(std::back_inserter(output), "{}", value);
} else {
static_assert(false, "UNSUPPORTED TYPE!!!");
}
return AdcSerializerErrorCode::ERROR_OK;
}
};
template <typename VT>
struct AdcDeserializer : AdcDeserializerBase {
static constexpr std::string_view deserializerName{"ADC-FALLBACK-DESERIALIZER"};
virtual ~AdcDeserializer() = default;
template <adc_serialization_params_c ParamsT = adc_serialization_params_t>
error_t operator()(traits::adc_input_char_range auto const& input,
VT& value,
ParamsT const& params = adc_serialization_params_t{})
{
if constexpr (std::is_arithmetic_v<VT>) {
auto v = adc::utils::AdcFromChars<VT>(utils::AdcTrimSpaces(input));
if (!v.has_value()) {
return AdcDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
}
value = v.value();
} else if constexpr (adc::traits::adc_output_char_range<VT>) {
VT r;
if constexpr (traits::adc_fixed_size_range<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!!!");
AdcDeserializer<el_t> dsr;
return deserializingRange<el_t>(dsr, input, value, params);
} else if constexpr (traits::adc_tuple_like<VT>) {
bool empty;
auto elems = splitValueIntoElements(input, params, &empty);
if (empty) {
value = VT{};
} else {
return [&input, &params, &elems]<size_t I = 0>(this auto& self, VT& tp) {
if constexpr (I < std::tuple_size_v<VT>) {
if (I < elems.size()) {
auto err =
AdcDeserializer<std::tuple_element_t<I, VT>>{}(elems[I], std::get<I>(tp), params);
if (err) {
return AdcDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER;
}
return self.template operator()<I + 1>(tp);
} else {
return AdcDeserializerErrorCode::ERROR_OK;
}
}
return AdcDeserializerErrorCode::ERROR_OK;
}(value);
}
} else if constexpr (traits::adc_time_point_c<VT>) {
std::istringstream ist{utils::AdcTrimSpaces<std::string>(input)};
std::chrono::from_stream(ist, params.timepoint_format.c_str(), value);
if (ist.fail()) {
return AdcDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
}
} else if constexpr (traits::adc_time_duration_c<VT>) {
typename VT::rep vd;
AdcDeserializer<typename VT::rep> dsr;
auto err = dsr(utils::AdcTrimSpaces(input), vd, params);
if (err) {
return adc_deduced_err(err, AdcDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
}
value = VT{vd};
} else {
static_assert(false, "UNSUPPORTED VALUE TYPE!!!");
}
return AdcDeserializerErrorCode::ERROR_OK;
}
};
} // namespace adc