#pragma once /* ABSTRACT DEVICE COMPONENTS LIBRARY */ #include #include #include #include "adc_traits.h" #include "adc_utils.h" namespace adc { /* SERIALIZATION/DESERIALIZATION PROCESS ERROR */ template concept adc_serialization_error_c = std::default_initializable && (std::convertible_to || 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 concept adc_serialization_params_c = std::copyable && requires(T t) { // delimiter between items of serializing values sequence requires traits::adc_output_char_range; // delimiter between items of aggregative (multi-element) serializing value requires traits::adc_output_char_range; // a format string for std::chrono::time_point types requires traits::adc_output_char_range; }; // 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 struct adc_serializer_interface_t { virtual ~adc_serializer_interface_t() = default; typedef RetT error_t; template SelfT, traits::adc_output_char_range R, typename ValueT> RetT operator()(this SelfT&& self, R& output, ValueT const& value) { return std::forward(self)(output, value); } template 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(self)(output, value, params); } protected: adc_serializer_interface_t() = default; }; template concept adc_serializer_c = std::derived_from> && requires(T t, const T t_const) { // static const variable with name of the serializer requires std::formattable && std::is_const_v; }; template struct adc_deserializer_interface_t { virtual ~adc_deserializer_interface_t() = default; typedef RetT error_t; template SelfT, traits::adc_input_char_range R, typename ValueT> RetT operator()(this SelfT&& self, R const& input, ValueT& value) { return std::forward(self)(input, value); } template 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(self)(input, value, params); } protected: adc_deserializer_interface_t() = default; }; template concept adc_deserializer_c = std::derived_from> && requires(T t, const T t_const) { // static const variable with name of the deserializer requires std::formattable && std::is_const_v; }; } // 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 : public true_type { }; template <> class is_error_code_enum : 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(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(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 { virtual ~AdcSerializerBase() = default; using typename adc_serializer_interface_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 requires(std::ranges::input_range && std::same_as>) 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 { using typename adc_deserializer_interface_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 splitValueIntoElements(traits::adc_input_char_range auto const& input, adc_serialization_params_c auto const& params, bool& empty) { static_assert(std::ranges::contiguous_range, "NOT IMPLEMENTED FOR NON-CONTIGUIUS RANGES!!!"); std::vector 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{el.begin(), el.end()}); if (empty && res.back().size()) { empty = false; } }); } else { empty = true; } return res; } template 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(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) { std::back_inserter(r) = val; it = r.end(); } } else { *it = val; ++it; } } return AdcDeserializerErrorCode::ERROR_OK; } }; /* MAIN (FALLBACK) TEMPLATED IMPLEMENTATION OF SERIALIZER/DESERIALIZER */ template struct AdcSerializer : AdcSerializerBase { constexpr static std::string_view serializerName{"ADC-FALLBACK-SERIALIZER"}; template 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) { std::string s = value; std::ranges::copy(s, std::back_inserter(output)); } else if constexpr (std::ranges::range) { using value_t = std::remove_cv_t>; // special range (character sequence) if constexpr (std::same_as) { std::ranges::copy(value, std::back_inserter(output)); } else { AdcSerializer sr; return AdcSerializerBase::serializeRange(sr, value, output, params); } } else if constexpr (traits::adc_tuple_like) { return [&output, ¶ms](this auto& self, VT& tp) -> error_t { if constexpr (I < (std::tuple_size_v - 1)) { auto err = AdcSerializer>{}(output, std::get(tp), params); if (err) { return AdcSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER; } AdcSerializerBase::addElemDelimiter(output, params); return self.template operator()(tp); } else if constexpr (I < (std::tuple_size_v - 1)) { // the last element auto err = AdcSerializer>{}(output, std::get(tp), params); if (err) { return AdcSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER; } return AdcSerializerErrorCode::ERROR_OK; } }(value); } else if constexpr (traits::adc_time_point_c) { 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) { std::format_to(std::back_inserter(output), "{}", value.count()); } else if constexpr (std::formattable) { std::format_to(std::back_inserter(output), "{}", value); } else { static_assert(false, "UNSUPPORTED TYPE!!!"); } return AdcSerializerErrorCode::ERROR_OK; } }; template struct AdcDeserializer : AdcDeserializerBase { static constexpr std::string_view deserializerName{"ADC-FALLBACK-DESERIALIZER"}; virtual ~AdcDeserializer() = default; template 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) { auto v = adc::utils::AdcFromChars(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 r; if constexpr (traits::adc_fixed_size_range) { 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!!!"); AdcDeserializer dsr; return deserializingRange(dsr, input, value, params); } else if constexpr (traits::adc_tuple_like) { bool empty; auto elems = splitValueIntoElements(input, params, &empty); if (empty) { value = VT{}; } else { return [&input, ¶ms, &elems](this auto& self, VT& tp) { if constexpr (I < std::tuple_size_v) { if (I < elems.size()) { auto err = AdcDeserializer>{}(elems[I], std::get(tp), params); if (err) { return AdcDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER; } return self.template operator()(tp); } else { return AdcDeserializerErrorCode::ERROR_OK; } } return AdcDeserializerErrorCode::ERROR_OK; }(value); } } else if constexpr (traits::adc_time_point_c) { std::istringstream ist{utils::AdcTrimSpaces(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) { typename VT::rep vd; AdcDeserializer 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