Files
mcc/mcc_serialization_common.h
2026-02-04 18:29:08 +03:00

391 lines
15 KiB
C++

#pragma once
/****************************************************************************************
* *
* MOUNT CONTROL COMPONENTS LIBRARY *
* *
* *
* COMMON DEFINITIONS FOR DATA SERIALIZATION/DESERIALIZATION *
* *
****************************************************************************************/
#include "mcc_concepts.h"
#include "mcc_error.h"
#include "mcc_traits.h"
namespace mcc
{
/* celestial angle serialization */
enum class MccSerializedAngleFormat {
MCC_SERIALIZED_FORMAT_DEGREES, // degrees as floating-point number
MCC_SERIALIZED_FORMAT_SXGM_HOURS, // sexagesimal representation: hours:mins:secs
MCC_SERIALIZED_FORMAT_SXGM_DEGS, // sexagesimal representation: degs:arcmins:arcsecs
MCC_SERIALIZED_FORMAT_UNKNOWN
};
static constexpr std::string_view MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR = "SRANG-FORMAT-DEGREES";
static constexpr std::string_view MCC_SERIALIZED_ANG_FORMAT_SXGM_HOURS_STR = "SRANG-FORMAT-SXGM_HOURDEG";
static constexpr std::string_view MCC_SERIALIZED_ANG_FORMAT_SXGM_DEGS_STR = "SRANG-FORMAT-SXGM_DEGDEG";
static constexpr std::string_view MccSerializedAngleFormatToStr(MccSerializedAngleFormat fmt)
{
return fmt == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES ? MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR
: fmt == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS
? MCC_SERIALIZED_ANG_FORMAT_SXGM_HOURS_STR
: fmt == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS ? MCC_SERIALIZED_ANG_FORMAT_SXGM_DEGS_STR
: MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR;
}
template <traits::mcc_input_char_range R>
static constexpr MccSerializedAngleFormat MccSerializedAngleFormatStrToValue(R&& str)
{
if constexpr (std::is_array_v<std::decay_t<R>>) {
return MccSerializedAngleFormatStrToValue(std::string_view{str});
}
const auto hash = mcc::utils::FNV1aHash(std::forward<R>(str));
return hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR)
? MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES
: hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_ANG_FORMAT_SXGM_HOURS_STR)
? MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS
: hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_ANG_FORMAT_SXGM_DEGS_STR)
? MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS
: MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_UNKNOWN;
}
/* coordinates pair serialization */
enum class MccSerializedCoordPairFormat {
MCC_SERIALIZED_FORMAT_DEGREES, // both angles are in degrees as floating-point number
MCC_SERIALIZED_FORMAT_SXGM_HOURDEG, // X is in hour and Y is in degree sexagesimal representation
MCC_SERIALIZED_FORMAT_SXGM_DEGDEG, // both angles are in sexagesimal degrees
MCC_SERIALIZED_FORMAT_UNKNOWN
};
static constexpr std::string_view MCC_SERIALIZED_CP_FORMAT_DEGREES_STR = "SRCP-FORMAT-DEGREES";
static constexpr std::string_view MCC_SERIALIZED_CP_FORMAT_SXGM_HOURDEG_STR = "SRCP-FORMAT-SXGM_HOURDEG";
static constexpr std::string_view MCC_SERIALIZED_CP_FORMAT_SXGM_DEGDEG_STR = "SRCP-FORMAT-SXGM_DEGDEG";
static constexpr std::string_view MccSerializedCoordPairFormatToStr(MccSerializedCoordPairFormat fmt)
{
return fmt == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_DEGREES ? MCC_SERIALIZED_CP_FORMAT_DEGREES_STR
: fmt == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG
? MCC_SERIALIZED_CP_FORMAT_SXGM_HOURDEG_STR
: fmt == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGDEG
? MCC_SERIALIZED_CP_FORMAT_SXGM_DEGDEG_STR
: MCC_SERIALIZED_CP_FORMAT_DEGREES_STR;
}
template <traits::mcc_input_char_range R>
static constexpr MccSerializedCoordPairFormat MccSerializedCoordPairFormatStrToValue(R&& str)
{
if constexpr (std::is_array_v<std::decay_t<R>>) {
return MccSerializedCoordPairFormatStrToValue(std::string_view{str});
}
const auto hash = mcc::utils::FNV1aHash(std::forward<R>(str));
return hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_CP_FORMAT_DEGREES_STR)
? MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_DEGREES
: hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_CP_FORMAT_SXGM_HOURDEG_STR)
? MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG
: hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_CP_FORMAT_SXGM_DEGDEG_STR)
? MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGDEG
: MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_UNKNOWN;
}
/* precision of representation of serialized celestial angle/coordinates pair */
struct MccSerializedAngleFormatPrec {
uint8_t hour_prec = 2; // number of decimal places in hour seconds (sexagesimal format)
uint8_t deg_prec = 1; // number of decimal places in arcseconds (sexagesimal format)
// slightly better than 0.1 arcsecond precision
uint8_t decimals = 6; // number of decimal places in degrees (floating-point number format)
// if 0, then number of decimal places is according to formating rules of 'double' type
};
enum class MccTimePointFormat {
MCC_TIMEPOINT_FORMAT_DATE, // UTC date
MCC_TIMEPOINT_FORMAT_MJD, // MJD
MCC_TIMEPOINT_FORMAT_JD, // JD
MCC_TIMEPOINT_FORMAT_JEPOCH, // Julian epoch
MCC_TIMEPOINT_FORMAT_UNKNOWN
};
static constexpr std::string_view MCC_TIMEPOINT_FORMAT_DATE_STR = "TP-FORMAT-DATE";
static constexpr std::string_view MCC_TIMEPOINT_FORMAT_MJD_STR = "TP-FORMAT-MJD";
static constexpr std::string_view MCC_TIMEPOINT_FORMAT_JD_STR = "TP-FORMAT-JD";
static constexpr std::string_view MCC_TIMEPOINT_FORMAT_JEPOCH_STR = "TP-FORMAT-JEPOCH";
static constexpr std::string_view MccTimePointFormatToStr(MccTimePointFormat fmt)
{
return fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE ? MCC_TIMEPOINT_FORMAT_DATE_STR
: fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_MJD ? MCC_TIMEPOINT_FORMAT_MJD_STR
: fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JD ? MCC_TIMEPOINT_FORMAT_JD_STR
: fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JEPOCH ? MCC_TIMEPOINT_FORMAT_JEPOCH_STR
: MCC_TIMEPOINT_FORMAT_MJD_STR;
}
template <traits::mcc_input_char_range R>
static constexpr MccTimePointFormat MccTimePointFormatStrToValue(R&& str)
{
if constexpr (std::is_array_v<std::decay_t<R>>) {
return MccTimePointFormatStrToValue(std::string_view{str});
}
const auto hash = mcc::utils::FNV1aHash(std::forward<R>(str));
return hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_DATE_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE
: hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_MJD_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_MJD
: hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_JD_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JD
: hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_JEPOCH_STR)
? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JEPOCH
: MccTimePointFormat::MCC_TIMEPOINT_FORMAT_UNKNOWN;
}
/* SERIALIZATION/DESERIALIZATION PROCESS TUNING PARAMETERS */
// delimiter between items of serializing values sequence
static constexpr std::string_view MCC_SERIALIZING_DEFAULT_SEQ_DELIMITER{";"};
// delimiter between items of aggregative (multi-element) serializing value
static constexpr std::string_view MCC_SERIALIZING_DEFAULT_ELEM_DELIMITER{","};
template <typename T>
concept mcc_serialization_params_c = requires(T t) {
requires traits::mcc_output_char_range<decltype(t.seq_delim)>;
requires traits::mcc_output_char_range<decltype(t.elem_delim)>;
requires std::same_as<decltype(t.angle_format), MccSerializedAngleFormat>;
requires std::same_as<decltype(t.angle_prec), MccSerializedAngleFormatPrec>;
requires std::same_as<decltype(t.coordpair_format), MccSerializedCoordPairFormat>;
requires std::same_as<decltype(t.timepoint_format), MccTimePointFormat>;
// a format string for mcc_systime_c types (std;:chrono::sys_time)
requires std::same_as<decltype(t.systime_format), std::string_view>;
// if true - normalize angle in sexagesimal format (to control rounding)
// (to avoid something like "24:00:00.0" for sexagesimal 'hours:minutes:seconds' format)
requires std::convertible_to<decltype(t.norm_sxgm), bool>;
// if true - interpretate serialized angle in sexagesimal format as 'hours:minutes:seconds'
// otherwise as 'degrees:arcmins:arcsecs'
requires std::convertible_to<decltype(t.sxgm_hms), bool>;
};
/* SERIALIZER/DESERIALIZER CONCEPTS */
template <mcc_error_c RetT>
struct mcc_serializer_interface_t {
virtual ~mcc_serializer_interface_t() = default;
typedef RetT error_t;
template <std::derived_from<mcc_serializer_interface_t> SelfT, traits::mcc_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<mcc_serializer_interface_t> SelfT, traits::mcc_output_char_range R, typename ValueT>
RetT operator()(this SelfT&& self, R& output, ValueT const& value, mcc_serialization_params_c auto const& params)
{
return std::forward<SelfT>(self)(output, value, params);
}
protected:
mcc_serializer_interface_t() = default;
};
template <typename T>
concept mcc_serializer_c =
std::derived_from<T, mcc_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)>;
// // must define a type "params_t"
// requires mcc_serialization_params_c<typename T::params_t>;
// { t.setParams(std::declval<typename T::params_t const&>()) };
// { t_const.getParams() } -> std::same_as<typename T::params_t>;
};
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);
}
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, mcc_serialization_params_c auto& params)
{
return std::forward<SelfT>(self)(input, value, params);
}
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>> && 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)>;
// // must define a type "params_t"
// requires mcc_serialization_params_c<typename T::params_t>;
// { t.setParams(std::declval<typename T::params_t const&>()) };
// { t_const.getParams() } -> std::same_as<typename T::params_t>;
};
/* BASE CLASS IMPLEMENTATION FOR SERIALIZER/DESERIALIZER */
namespace impl
{
// default definition of serialization/deserialization process parameters structure
struct mcc_serialization_params_t {
std::string seq_delim{MCC_SERIALIZING_DEFAULT_SEQ_DELIMITER};
std::string elem_delim{MCC_SERIALIZING_DEFAULT_ELEM_DELIMITER};
MccSerializedAngleFormat angle_format{MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES};
MccSerializedAngleFormatPrec angle_prec{MccSerializedAngleFormatPrec{.hour_prec = 2, .deg_prec = 1, .decimals = 6}};
MccSerializedCoordPairFormat coordpair_format{MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG};
MccTimePointFormat timepoint_format{MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE};
std::string_view systime_format{"{:%FT%T}"};
bool norm_sxgm{false};
bool sxgm_hms{false};
};
static_assert(mcc_serialization_params_c<mcc_serialization_params_t>, "!!!");
namespace details
{
template <mcc_serialization_params_c ParamsT>
struct _params_manipulator_t {
virtual ~_params_manipulator_t() = default;
typedef ParamsT params_t;
template <mcc_serialization_params_c p_t>
void setParams(p_t const& pars)
{
if constexpr (std::same_as<p_t, params_t>) {
_params = pars;
} else {
_params.seq_delim = pars.seq_delim;
_params.elem_delim = pars.elem_delim;
_params.coordpair_format = pars.coordpair_format;
_params.angle_prec = pars.angle_prec;
_params.timepoint_format = pars.timepoint_format;
_params.norm_sxgm = pars.norm_sxgm;
_params.sxgm_hms = pars.sxgm_hms;
}
}
template <mcc_serialization_params_c p_t>
requires(!std::same_as<p_t, params_t>)
p_t getParams() const
{
p_t pars;
pars.seq_delim = _params.seq_delim;
pars.elem_delim = _params.elem_delim;
pars.coordpair_format = _params.coordpair_format;
pars.angle_prec = _params.angle_prec;
pars.timepoint_format = _params.timepoint_format;
pars.norm_sxgm = _params.norm_sxgm;
pars.sxgm_hms = _params.sxgm_hms;
return pars;
}
params_t getParams() const
{
return _params;
}
protected:
_params_manipulator_t() = default;
params_t _params;
};
} // namespace details
struct MccDeserializerBase : mcc_deserializer_interface_t<MccError> {
virtual ~MccDeserializerBase() = default;
using typename mcc_deserializer_interface_t<MccError>::error_t;
protected:
MccDeserializerBase() = default;
};
// template <mcc_serialization_params_c ParamsT>
// struct MccSerializerBase : mcc_serializer_interface_t<MccError>, details::_params_manipulator_t<ParamsT> {
// virtual ~MccSerializerBase() = default;
// using typename mcc_serializer_interface_t<MccError>::error_t;
// using typename details::_params_manipulator_t<ParamsT>::params_t;
// protected:
// MccSerializerBase() = default;
// };
// template <mcc_serialization_params_c ParamsT>
// struct MccDeserializerBase : mcc_deserializer_interface_t<MccError>, details::_params_manipulator_t<ParamsT> {
// virtual ~MccDeserializerBase() = default;
// using typename mcc_deserializer_interface_t<MccError>::error_t;
// using typename details::_params_manipulator_t<ParamsT>::params_t;
// protected:
// MccDeserializerBase() = default;
// };
} // namespace impl
} // namespace mcc